Java 如何打印整个字符串池?
我想打印整个字符串池,其中包含在垃圾收集之前使用Java 如何打印整个字符串池?,java,string,Java,String,我想打印整个字符串池,其中包含在垃圾收集之前使用intern()添加的文本和string对象 对于这种操作,JDK是否有一个隐式方法?如何检查字符串池?,因此GC在清理任何对象之前调用finalize方法 因此字符串中的finalize方法也被调用。但遗憾的是,String是最后一个类,您不能重写它。() 但是如果你真的想让这个东西工作起来,那么你需要创建你自己的字符串对象,命名为其他东西,但是内部行为将保留所有的字符串函数 为了保证GC的安全,请尝试以下内容:编辑:评论表明,对于这种“黑客”的
intern()
添加的文本和string
对象
对于这种操作,JDK是否有一个隐式方法?如何检查字符串池?,因此GC在清理任何对象之前调用finalize方法
因此字符串中的finalize方法也被调用。但遗憾的是,String是最后一个类,您不能重写它。()
但是如果你真的想让这个东西工作起来,那么你需要创建你自己的字符串对象,命名为其他东西,但是内部行为将保留所有的字符串函数
为了保证GC的安全,请尝试以下内容:编辑:评论表明,对于这种“黑客”的作用可能存在误解。它打印通过(直接或间接)调用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);
}
}
可以安全地用
h = 0;
4.更改新String
类的String#intern()
方法。最初,这是一种本机方法。它可以被以下内容替换
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;
导入javax.swing.JFrame;
导入javax.swing.JTable;
导入javax.swing.SwingUtilities;
公共类NewStringTest
{
公共静态void main(字符串[]args)
{
生成中间字符串();
System.out.println(StringPool.getPool());
}
私有静态void generateSomeString()
{
String s=“这是一些测试字符串”;
对于(int i=0;iOverrideString
并在实习前存储它们;)@NeplatnyUdaj:String
是final
。但是我们不能重写String?我以为interned String永远不会被GCed…那么创建一个新的String实现并通过Xbootclasspath
提供它怎么样?我不知道是否可以加载不同的String…你的intern()
replacement被破坏,因为它无条件返回this
,不考虑映射中的现有实例。但更糟糕的是,此黑客显然只捕获intern()
的显式调用-请注意,您的输出不包含文本“这是一些测试字符串”
,但只有您手动实习的编号版本。当我使用-XX:+PrintStringTableStatistics
在未经修改的环境中运行您的程序时,JVM说大约有4000个实习字符串…@Holger虽然标题更一般,但问题涉及实习()
method。实习也发生在类加载和虚拟机启动级别,绕过intern()
调用,这一事实使事情变得困难(在将此应用于时可以看出,这可能也导致您出现这种情况)。不过,我看不到访问字符串池的任何其他选项(手工定制的JVM黑客除外)。但请随意提供其他建议作为答案。这不仅仅是标题;问题的主体还说“整个字符串池包含使用intern()
”添加的文本和字符串对象@Holger因此,答案是:“这是不可能的”。我想是的。JVMTI允许获取所有现有的String
实例,但似乎无法检查某个特定实例是否已合并…finalize()
方法与此无关,创建一个新的String
类不会帮助您查看合并的文本。
java -Xbootclasspath:newString.jar;C:\jre\lib\rt.jar NewStringTest
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();
}
}
}