如何打印整个String池?

我想在垃圾收集之前打印整个字符串池,其中包含使用intern()添加的文字和String对象。

是否存在JDK隐含的此类操作方法? 我们如何检查字符串池?

编辑:评论表明可能存在对这种“黑客”行为的误解。 它打印由(直接或间接)调用intern()的字符串,如问题中所述。 它不会打印“整个字符串池”,因为字符串池只驻留在JVM中,填充了在类加载和初始化期间出现的符号和字符串,并且无法从Java端访问。


NeplatnyUdaj在评论中提到可能有可能定义一个新的java.lang.String类并在启动时将其隐藏到JVM中。 我很好奇,并试了一下。 我该怎么说:它有效!

1.创建一个包含java.lang包的新项目

2.将这样的类插入此包中

 package java.lang; import java.util.LinkedHashSet; import java.util.Set; public class StringPool { private static Set pool = null; public static synchronized void store(String string) { try { if (pool == null) { pool = new LinkedHashSet(); } pool.add(string); } catch (Exception e) { // Ignore } } public static synchronized Set getPool() { return new LinkedHashSet(pool); } } 

3.将原始java.lang.String类复制并粘贴到此包中。 令人惊讶的是,这没有太多问题。 它会抱怨一个function,即呼叫

  h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length); 

可以安全地替换为

  h = 0; 

4.更改新String类的String#intern()方法。 最初,这是一种native方法。 它可以用类似的东西代替

 public String intern() { StringPool.store(this); return this; } 

5.从此项目创建.JAR文件,并将其存储为newString.jar

6.使用生成/包含/使用某些字符串的测试类创建另一个项目。 (这应该很简单)并编译这个类,可以命名为NewStringTest

7.使用修改后的字符串类启动测试程序:

 java -Xbootclasspath:newString.jar;C:\jre\lib\rt.jar NewStringTest 

然后可以使用StringPool#getPool()方法获取包含实习字符串的池。



我刚用下面的类测试了这个,它手动创建了一些字符串,以及一些Swing组件(可以预期包含一些字符串):

 import java.lang.reflect.InvocationTargetException; import javax.swing.JFrame; import javax.swing.JTable; import javax.swing.SwingUtilities; public class NewStringTest { public static void main(String[] args) { generateSomeStrings(); System.out.println(StringPool.getPool()); } private static void generateSomeStrings() { String s = "This is some test string"; for (int i=0; i<10; i++) { String t = s + i; t.intern(); } try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { JFrame frame = new JFrame(); JTable table = new JTable(); } }); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } 

输出是

[hashSeed,value,buf,J,D,Z,seed,segmentShift,segmentMask,segments,state,head,tail,waitStatus,next,Ljava / lang / String;,I,[C,[J,Ljava / util / Hashtable;,Ljava / security / PermissionCollection;,Ljava / util / Vector;,Ljava / lang / Class;,main,这是一些测试string0,这是一些测试string1,这是一些测试string2,这是一些测试string3,这是一些测试string4,这是一些测试string5,这是一些测试string6,这是一些测试string7,这是一些测试string8,这是一些测试string9,INSTANCE,es,ES,sv,SE,值,Ljava / lang / Object;,[Ljava / awt / Component;,Ljava / awt / LayoutManager;,Ljava / awt / LightweightDispatcher;,Ljava / awt / Dimension;,createUI,invoke,VK_F10,VK_CONTEXT_MENU,VK_SPACE,VK_LEFT,VK_KP_LEFT,VK_RIGHT ,VK_KP_RIGHT,VK_ESCAPE,VK_C,VK_V,VK_X,VK_COPY,VK_PASTE,VK_CUT,VK_INSERT,VK_DELETE,VK_DOWN,VK_KP_DOWN,VK_UP,VK_KP_UP,VK_HOME,VK_END,VK_PAGE_UP,VK_PAGE_DOWN,VK_TAB,VK_ENTER,VK_A,VK_SLASH,VK_BACK_SLASH,VK_F2,VK_F8 ]

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#finalize%28%29 ,因此GC在清理任何对象之前调用finalize方法。

所以String中的finalize方法也被调用了。 但遗憾的是,String是最后一堂课,你无法覆盖它。 ( 为什么String类在Java中声明为final? )

但是如果你真的想让这个东西工作,那么你需要创建一个名为else的自己的字符串对象,但内部行为将保留所有字符串的function。

对于有保证的GC,请尝试以下操作: http : //code.google.com/p/jlibs/wiki/GarbageCollection