¿Cómo imprimir todo el grupo de cadenas?

Quería imprimir todo el grupo de cadenas que contiene literales y objetos de String añadidos usando intern() justo antes de la recolección de basura.

¿Hay algún método implícito para JDK para tal operación? ¿Cómo podemos inspeccionar el grupo de cadenas?

EDITAR: El comentario sugiere que puede haber un malentendido con respecto a lo que hace este “truco”. Imprime las cadenas que han sido internados (directa o indirectamente) llamando a intern() , como se describe en la pregunta. No imprimirá el “conjunto de cadenas completo”, ya que el grupo de cadenas solo reside en la JVM, está lleno de símbolos y cadenas que aparecen durante la carga de clases y la inicialización, y no es accesible desde el lado de Java.


NeplatnyUdaj mencionó en un comentario que podría ser posible definir una nueva clase java.lang.String e introducir esto en la JVM al inicio. Tenía curiosidad y lo probé. Y qué debería decir: ¡Funciona!

1. Crea un nuevo proyecto que contenga el paquete java.lang

2. Inserta una clase como esta en este paquete

 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. Copie y pegue la clase original java.lang.String en este paquete. Sorprendentemente, esto funciona sin muchos problemas. Se quejará de una sola función, a saber, una llamada a

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

que puede ser reemplazado con seguridad

  h = 0; 

4. Cambie el método String#intern() de la nueva clase String . Originalmente, este es un método native . Se puede reemplazar con algo así como

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

5. Cree un archivo .JAR a partir de este proyecto y guárdelo, por ejemplo, como newString.jar

6. Cree otro proyecto con una clase de prueba que genere / contenga / use algunas cadenas. (eso debería ser fácil) y comstackr esta clase, que se puede NewStringTest

7. Inicie el progtwig de prueba con la clase de cadena modificada:

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

El StringPool#getPool() se puede usar para obtener el grupo que contiene las cadenas internas.



Acabo de probar esto con la siguiente clase, que crea manualmente algunas cadenas y algunos componentes Swing (que se puede esperar que contengan algunas cadenas):

 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(); } } } 

Y la salida es

[hashSeed, value, buf, J, D, Z, seed, segmentShift, segmentMask, segmentos, estado, head, tail, waitStatus, next, Ljava / lang / String ;, I, [C, [J, Ljava / util / Hashtable ;, Ljava / security / PermissionCollection ;, Ljava / util / Vector ;, Ljava / lang / Class ;, main, esta es una cadena de prueba0, esta es una cadena de prueba1, esta es una cadena de prueba2, esta es una cadena de prueba3, Esto es una cadena de prueba4, esta es una cadena de prueba5, esta es una cadena de prueba6, esta es una cadena de prueba7, esta es una cadena de prueba8, esta es una cadena de prueba9, INSTANCIA, es, ES, sv, SE, valores, 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 , por lo que el GC llama al método de finalización antes de limpiar cualquiera de los objetos.

Por lo tanto, también se llama al método de finalización en String. Pero, lamentablemente, String es una clase final y no puedes anularla. ( ¿Por qué la clase String se declara definitiva en Java? )

Pero si realmente desea que esto funcione, entonces necesita crear su propio objeto de cadena llamado algo diferente, pero el comportamiento interno mantendrá todas las funciones de cadenas.

Y para un GC garantizado, pruebe esto: http://code.google.com/p/jlibs/wiki/GarbageCollection