如何打印整个String池?

Pra*_*ant 11 java string

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

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

Mar*_*o13 13

编辑:评论表明可能存在对这种"黑客"行为的误解.它打印已经(直接或间接)调用的字符串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<String> pool = null;
    public static synchronized void store(String string)
    {
        try
        {
            if (pool == null)
            {
                pool = new LinkedHashSet<String>();
            }
            pool.add(string);
        }
        catch (Exception e)
        {
            // Ignore
        }
    }

    public static synchronized Set<String> getPool()
    {
        return new LinkedHashSet<String>(pool);
    }

}
Run Code Online (Sandbox Code Playgroud)

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

    h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length);
Run Code Online (Sandbox Code Playgroud)

可以安全地替换

    h = 0;
Run Code Online (Sandbox Code Playgroud)

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

public String intern()
{
    StringPool.store(this);
    return this;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

java -Xbootclasspath:newString.jar;C:\jre\lib\rt.jar NewStringTest
Run Code Online (Sandbox Code Playgroud)

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是

[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 ]

  • 您的`intern()`替换项已损坏,因为它无条件返回`this`,而不考虑映射中的现有实例。但更糟糕的是,这种黑客显然只捕获了对`intern()`的显式调用-请注意,您的输出不包含程序的原义“这是一些测试字符串”,而是仅包含您手动插入的编号版本。当我使用-XX:+ PrintStringTableStatistics在未修改的环境中运行您的程序时,JVM表示大约有4000个内联字符串… (2认同)
  • 不只是标题 问题的主体还说“ *整个字符串池,包含文字量*和*使用`intern()添加的字符串对象*” (2认同)

din*_*707 -1

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

所以 String 中的 Finalize 方法也会被调用。但遗憾的是 String 是最终类,您无法覆盖它。(为什么在Java中String类被声明为final?

但是如果你真的想让这个东西发挥作用,那么你需要创建自己的字符串对象,命名为其他东西,但内部行为将保留所有字符串功能。

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