2009-12-02 24 views
34

que veo un montón de código heredado así:Cuándo utilizar pasante() en literales de cadena

class A { 
    public static final String CONSTANT = "value".intern(); 
    ... 
} 

No veo ninguna razón para que el interno(), como en el Javadoc se puede leer: "Todas las cadenas literales y las expresiones constantes con valores de cadena están intercaladas". ¿Hay alguna intención de esto, tal vez en revisiones pasadas del lenguaje?

+7

¿Alguien más que pjp realmente leyó esta pregunta antes de contestarla? – Adamski

+0

posible duplicado de [¿Están todas las constantes de tiempo de compilación en línea?] (Http://stackoverflow.com/questions/377819/are-all-compile-time-constants-inlined) –

Respuesta

65

Esta es una técnica para asegurar que CONSTANT en realidad no es una constante.

Cuando el compilador de Java ve una referencia a una primitiva estática final o String, inserta el valor real de esa constante en la clase que lo utiliza. Si luego cambia el valor constante en la clase de definición pero no recompila la clase que usa, continuará usando el valor anterior.

Al llamar a intern() en la cadena "constante", el compilador ya no lo considera una constante estática, por lo que la clase en uso accederá al miembro de la clase definitoria en cada uso.

citas

JLS:

+4

Ahora eso es lo que llamaría un truco – pjp

+1

Acabo de confirmar esto experimentalmente, pero ¿hay una cita de JLS? –

+0

Esto es similar a http://stackoverflow.com/questions/377819/are-all-compile-time-constants-inlined – pjp

16

El uso de intern() con la constante de cadena literal es una pérdida de tiempo que el literal ya estará internado como se especifica por la sección 3.10.5. String Literals de The Java® Language Specification.

Citando de Java SE 8 Edición:

Por otra parte, una cadena literal se refiere siempre a la misma instancia de la clase String. Esto se debe a que los literales de cadena (o, más generalmente, las cadenas que son los valores de las expresiones constantes (§15.28)) son "internados" para compartir instancias únicas, utilizando el método String.intern.

Supongo que el codificador no apreció este hecho.

Editar:

Como kdgregory ha señalado que hay un impacto en cómo esta constante puede ser inline.

1-https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5

+3

El JLS habla sobre los resultados, pero no está claro si este plegamiento ocurre en tiempo de compilación, o si es solo que no debe haber una diferencia observable entre plegado en tiempo de compilación y concatenado y luego interno en tiempo de ejecución. La inspección del código de bytes respondería si dos literales concatenados de cadena se convierten en uno en el archivo de clase. – seh

5

Hace un tiempo hice prácticas() ed all o f las cadenas que provienen de los archivos de clase (para un analizador de archivos de clase). Intern() hizo que el programa utilizara menos memoria (no lo hará en este caso, como otros lo han señalado), pero ralentizó significativamente el programa (creo que tomó 4 segundos analizar todo rt.jar y ese cambio lo puso más de 8 segundos). Al analizarlo en ese momento (creo que era JDK 1.4), el código interno() es bastante feo y más lento que probablemente deba serlo.

Si tuviera que considerar llamar a intern() en mi código, primero lo perfilaría sin pasante() y luego lo perfilaría con interno() tanto para la memoria como para la velocidad y vería cuál es "peor" para el cambio.

+2

guau ... y los votos a la baja para obtener información precisa fueron para qué? ¿La información proporcionada es incorrecta? – TofuBeer

+0

de hecho, pjp fue bastante generoso con los votos a favor en esta pregunta –

+2

No me importan los votos a la baja ... solo la razón para ellos :-) – TofuBeer

0

He utilizado intern() para "bloqueo". Por ejemplo, digamos que tengo un "repositorio" de "registros comerciales". Mientras edito y actualizo una operación, quiero bloquear la operación; En su lugar, podría bloquear el tradeId.intern() para no tener que preocuparme por los clones de un comercio que esté flotando. No estoy seguro si a todos les gusta este uso.

Esto supone que el campo id es poco probable a chocar accidentalmente con el campo id de otro objeto de dominio - un TradeID no sucede a chocar con ACCOUNT_NUMBER por ejemplo, donde uno también podría estar haciendo

synchronized(account.getAccountNumber().intern()) {...} 

ver example

+0

¿No son básicamente los símbolos de Scala los que hacen String.intern()? –