generic java
¿El autoboxing llama a valueOf()? (4)
El tutorial de autoboxing de Oracle indica de manera práctica que li.add (i) está compilado para li.add (Integer.valueOf (i)), donde i es un int. Pero no sé si el tutorial debería considerarse una fuente autorizada.
Estoy ejecutando Oracle Java 1.7.0_72, parece que usa valueOf. A continuación se muestra un código y el bytecode para él. El bytecode muestra que está usando valueOf.
public class AutoBoxing {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
Integer x = 5;
int i = x;
System.out.println(x.toString());
}
}
Compiled from "AutoBoxing.java"
public class testing.AutoBoxing {
public testing.AutoBoxing();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: aload_1
6: invokevirtual #3 // Method java/lang/Integer.intValue:()I
9: istore_2
10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
13: aload_1
14: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
17: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: return
Pero no sé qué usa Open JDK. Lo probaré.
Estoy tratando de determinar si se garantiza que las siguientes afirmaciones son verdaderas:
((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
((Integer)1) == Integer.valueOf(1)
Siempre he supuesto que el autoboxing fue equivalente a llamar a valueOf()
en el tipo correspondiente. Cada discussion que he visto sobre el topic parece support mi suposición. Pero todo lo que pude encontrar en el JLS fue el siguiente ( §5.1.7 ):
Si el valor
p
se encasilla es un literal entero de tipoint
entre-128
y127
inclusive (§3.10.1), o el literal booleanotrue
ofalse
(§3.10.3), o un literal de carácter entre''/u0000''
y''/u007f''
inclusive (§3.10.4), entoncesb
son los resultados de dos conversiones de boxeo cualquiera dep
. Siempre es el caso quea == b
.
Eso describe un comportamiento idéntico similar al de valueOf()
. Pero no parece haber ninguna garantía de que valueOf()
se invoque realmente, lo que significa que podría haber una implementación teórica que mantenga un caché dedicado y separado para los valores de autoboxed. En tal caso, puede que no exista igualdad de identidad entre los valores almacenados en la memoria caché en caché y los valores normales en la caché.
El tutorial de autoboxing de Oracle indica de manera práctica que li.add(i)
está compilado para li.add(Integer.valueOf(i))
, donde i
es un int
. Pero no sé si el tutorial debería considerarse una fuente autorizada.
* Es una garantía ligeramente más débil que valueOf()
, ya que solo se refiere a valores literales.
Autoboxing se implementa completamente utilizando valueOf()
... en OpenJDK. Si esa es su implementación, siga leyendo ... si no, salte a continuación.
((Boolean)true) == Boolean.TRUE
((Boolean)true) == Boolean.valueOf(true)
La documentación de Java indica que Boolean.valueOf()
siempre devuelve Boolean.TRUE
o Boolean.FALSE
, por lo tanto, las comparaciones de referencia en estos casos tendrán éxito.
((Integer)1) == Integer.valueOf(1)
Para este ejemplo en particular, bajo la implementación OpenJDK con configuraciones predeterminadas, probablemente funcionará en virtud del hecho de que seleccionó un valor <128 que se almacena en caché al inicio (aunque esto puede ser anulado como una línea de comando arg). También puede funcionar para valores más grandes si se utiliza con frecuencia suficiente para ser almacenado en caché. A menos que esté trabajando bajo supuestos "seguros" sobre el caché Integer, no espere que la comparación de referencia sea una igualdad.
Long
, Short
, Character
y Byte
implementan incidentalmente este almacenamiento en caché también, pero a diferencia de Integer
, no se puede sintonizar. Byte
siempre funcionará si está comparando referencias de autobox / valueOf()
ya que, obviamente, no puede salir del rango. Float
y Double
, como era de esperar, siempre crearán una nueva instancia.
Ahora, en términos puramente genéricos? Consulte esta sección de JLS : DEBE recibir referencias iguales para boolean
y cualquier int
o char
dentro del rango de -128 a 127. No hay garantías para nada más.
Hasta que la especificación del lenguaje lo mencione, no se garantiza que el autoboxing sea equivalente a una llamada a los métodos valueOf
estáticos. Es un aspecto de implementación , no parte de la especificación de conversión de boxeo. Una implementación es teóricamente libre de usar otro mecanismo siempre que cumpla con la regla que mencionó desde el JLS.
En la práctica, hay muchos informes de errores Sun JDK (por ejemplo, JDK-4990346 y JDK-6628737 ) que implican claramente que cuando se introdujo el autoboxing en Java 5, la intención era hacer que el compilador confiara en valueOf
como se indica en JDK-6628737 :
Los métodos de fábrica estáticos Integer.valueOf (int), Long.valueOf (long), etc. se introdujeron en JDK 5 para que javac implemente el comportamiento de almacenamiento en caché requerido por la especificación de autoboxing.
Pero eso es solo para javac, no necesariamente para todos los compiladores.
Primero pensé que tu pregunta era una trampa de topic
Sin embargo, después de su comentario sobre @ElliottFrisch, me di cuenta de que era diferente:
Sé que el compilador se comporta de esa manera. Estoy tratando de averiguar si ese comportamiento está garantizado.
Para otros lectores, supongamos que "se comporta de esa manera" significa usar valueOf
.
Recuerde que hay compiladores múltiples para Java. Para ser "legales" deben seguir el contrato dado en el JLS . Por lo tanto, siempre que se respeten todas las reglas aquí, no hay garantía de cómo se implementa internamente el autoboxing.
Pero no veo ninguna razón para no usar valueOf
, especialmente que usa los valores en caché y es la forma recomendada según este artículo de Joseph D. Darcy.