如何打印整个String池? [英] How to print the whole String pool?
问题描述
我想打印包含文字的整个字符串池和字符串
使用 intern()
添加的对象垃圾收集。
I wanted to print the whole string pool which contains literals and String
objects added using intern()
just before garbage collection.
JDK是否存在隐含此类操作的方法?我们如何检查字符串池?
Is there a method implicit to JDK for such operation? How can we inspect the string pool?
推荐答案
编辑:评论表明可能存在误解关于这个黑客的作用。它打印已经(直接或间接)调用 intern()
实习的字符串,如问题中所述。它不会打印整个字符串池,因为字符串池只驻留在JVM中,填充了在类加载和初始化期间出现的符号和字符串,并且无法从Java端访问。
The comment suggests that there may be a misunderstanding regarding what this "hack" does. It prints the strings that have been interned by (directly or indirectly) calling intern()
, as described in the question. It will not print the "whole string pool", as the string pool only resides in the JVM, is filled with symbols and strings that appear during classloading and initialization, and not accessible from Java side.
NeplatnyUdaj在评论中提到可以定义一个新的 java.lang.String
class并在启动时将其隐藏到JVM中。我很好奇,并试了一下。我应该说什么:它有效!
NeplatnyUdaj mentioned in a comment that it might be possible to define a new java.lang.String
class and sneak this into the JVM at startup. I was curious, and tried it out. And what should I say: It works!
1。创建一个包含 java.lang包的新项目
2. 将此类课程插入此套餐
2. Insert a class like this into this package
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);
}
}
3。复制&将原始 java.lang.String
类粘贴到此包中。令人惊讶的是,这没有太多问题。它会抱怨一个函数,即调用
3. Copy & Paste the original java.lang.String
class into this package. Surprisingly, this works without many problems. It will complain about a single function, namely a call to
h = sun.misc.Hashing.murmur3_32(HASHING_SEED, value, 0, value.length);
可以安全地替换为
h = 0;
4. 更改字符串#intern( )
新 String
类的方法。最初,这是一个原生
方法。它可以替换为类似
4. Change the String#intern()
method of the new String
class. Originally, this is a native
method. It can be replaced with something like
public String intern()
{
StringPool.store(this);
return this;
}
5. 从此创建.JAR文件项目,并存储,例如, newString.jar
5. Create a .JAR file from this project, and store it, for example, as newString.jar
6。使用生成/包含/使用某些字符串的测试类创建另一个项目。 (这应该很简单)并编译这个类,可以命名为 NewStringTest
6. Create another project with a test class that generates/contains/uses some strings. (that should be easy) and compile this class, which may be named NewStringTest
7. 使用修改后的字符串类启动测试程序:
7. Launch the test program with the modified string class:
java -Xbootclasspath:newString.jar;C:\jre\lib\rt.jar NewStringTest
StringPool#getPool()然后可以使用
方法获取包含实习字符串的池。
The StringPool#getPool()
method can then be used to obtain the pool containing the interned strings.
我刚用下面的类测试了这个,它手动创建了一些字符串,以及一些Swing组件(可以预期包含一些字符串):
I just tested this with the following class, which manually creates some strings, and some Swing components (which can be expected to contain some strings):
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,
segment,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 ,调用,VK_F10,
VK_CONTEXT_MENU,VK_SPACE,VK_LEFT,VK_KP_LEFT,
VK_RIGHT,VK_KP_RIG HT,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]
[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, This is some test string0, This is some test string1, This is some test string2, This is some test string3, This is some test string4, This is some test string5, This is some test string6, This is some test string7, This is some test string8, This is some test string9, INSTANCE, es, , ES, sv, SE, values, 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]
这篇关于如何打印整个String池?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!