En este artículo, el autor le presentará una característica muy importante e interesante en Java, que es el boxeo y la unboxing automático, e interpretará los principios del boxeo automático y el unboxing del código fuente. Al mismo tiempo, esta característica también deja una trampa. Si los desarrolladores no prestan atención, fácilmente caerán en esta trampa.
Autoboxing
definición
Al escribir programas Java, las personas a menudo definen un objeto entero de las siguientes maneras:
Entero i = 100;
En el código anterior, puede saber que yo es una referencia del tipo entero y 100 es el tipo de datos básico en Java (tipo de datos primitivos). Este método de pasar directamente un tipo de datos básico a su clase de envoltorio correspondiente es el boxeo automático.
En JDK 1.5, el boxeo automático se introdujo por primera vez. Antes de JDK 1.5, si desea definir un objeto entero con un valor de 100, debe hacer esto:
Entero i = nuevo entero (100);
principio
Hagamos un punto de interrupción en el código anterior "entero i = 100;" y síguelo.
A continuación, podemos ver que el programa salta al método Value de (Int I) de la clase Integer.
/** * Devuelve una instancia <tt> entero </tt> que representa el valor especificado * <tt> int </tt>. * Si no se requiere una nueva instancia <tt> Integer </tt>, este método * generalmente debe usarse en preferencia al constructor * {@link #Integer (int)}, ya que es probable que este método produzca * rendimiento de tiempo significativamente mejor al almacenarse en caché * los valores solicitados frecuentemente. * * @param i an <code> int </code> valor. * @return a <tt> entero </tt> instancia que representa <tt> i </tt>. * @since 1.5 */ public static entero Value de (int i) {if (i> = -128 && i <= integerCache.high) return integerCache.cache [i + 128]; else devuelve nuevo entero (i); }En otras palabras, el embalaje es JDK que lo ayuda a completar la llamada a Integer.ValueOf (100).
Descomposición
definición
Entero entero100 = 100; int int100 = integer100;
En el código anterior, puede ver que Integer100 es una referencia al tipo entero, e int100 es un tipo de datos primitivo de tipo int. Sin embargo, podemos asignar un objeto de tipo entero a una variable de su tipo de datos original correspondiente. Esto es unboxing.
Unboxing es lo opuesto al embalaje. El boxeo es una variable que asigna un tipo de datos primitivos a la clase encapsulada correspondiente. Unboxing significa asignar una variable de una clase encapsulada a una variable del tipo de datos original correspondiente. Los nombres de embalaje y unboxing también son bastante apropiados.
principio
Creo que todos han adivinado lo que JDK hizo por nosotros durante el proceso de unboxing. Probemos nuestra conjetura a través de experimentos.
Establezca un punto de interrupción en la segunda línea del código anterior, es decir, establezca un punto de interrupción en "int100 = integer100;" y síguelo.
Podemos ver que el programa salta al método intValue () de Integer.
/** * Devuelve el valor de este <code> entero </code> como un * <code> int </code>. */ public int intValue () {Valor de retorno; }Es decir, JDK nos ayuda a completar la llamada al método intValue (). Para el experimento anterior, es llamar al método intValue () de Integer100 y asignar su valor de retorno a INT100.
Extendido
Experimento 1
Entero entero400 = 400; int int400 = 400; system.out.println (integer400 == int400);
En la tercera línea del código anterior, Integer400 e int400 ejecutan la ejecución ==. Y estos dos son diferentes tipos de variables. ¿El desempacado de Unboxing o INT400 se empacan? ¿Cuáles son los resultados de la operación?
== La operación es determinar si las direcciones de dos objetos son iguales o si los valores de los dos tipos de datos básicos son iguales. Por lo tanto, es fácil inferir que si Integer400 no está en caja, significa que los valores de los dos tipos básicos se comparan, y el resultado de la ejecución debe ser verdadero en este momento; Si INT400 está empaquetado, significa que las direcciones de los dos objetos son iguales, y el resultado de la ejecución debe ser falso en este momento. (En cuanto a por qué el autor los asigna a 400, está relacionado con las trampas que se discutirán más adelante).
Nuestro resultado de ejecución real es cierto. Por lo tanto, fue el Unboxing de Integer400. Los resultados del seguimiento de código lo demuestran.
Experimento 2
Entero entero100 = 100; int100 = 100; system.out.println (integer100.equals (int100));
En la tercera línea del código anterior, el parámetro del método Integer100 es INT100. Sabemos que los parámetros del método igual son objeto, no el tipo de datos básicos, por lo que aquí debe estar empaquetado int100. Los resultados del seguimiento de código lo demuestran.
De hecho, si el tipo de parámetro en un método es el tipo de datos original y el tipo de parámetro que se pasa es su clase de encapsulación, se unirá automáticamente; En consecuencia, si el tipo de parámetro en un método es el tipo de encapsulación y el tipo de parámetro pasado es su tipo de datos original, se cuadrará automáticamente.
Experimento 3
Integer Integer100 = 100; int100 = 100; Long Long200 = 200l; System.out.println (Integer100 + int100); System.out.println (Long200 == (Integer100 + int100)); System.Println (Long200.Equals (INTERGER100 + INT100));
En el primer experimento, hemos aprendido que cuando un tipo de datos básico realiza una operación == con la clase de encapsulación, la clase de encapsulación se unbogará. ¿Qué pasaría si +, -, *, /? Podemos saber en este experimento.
IF + Operación, el tipo de datos subyacente se cuadrará, entonces:
• En la línea 4, Integer100+INT100 obtendrá un objeto o de tipo entero y valor 200, y ejecutará el método toString () de este objeto y salida "200";
• En la línea 5, Integer100+INT100 obtendrá un objeto o de tipo entero y valor de 200. La operación == compara este objeto con un objeto Long200. Obviamente, False se emitirá;
• En la línea 6, Integer100+INT100 obtendrá un objeto O de tipo entero y valor 200. El método igual de Long compara Long200 con O, porque ambos son clases encapsuladas de diferentes tipos, por lo que la salida es falsa;
IF + Operation, la clase de encapsulación estará desanimada, entonces:
• En la línea 4, Integer100+INT100 obtendrá un tipo de datos básico de tipo B de tipo int y valor 200, luego el cuadro B para obtener O, ejecute el método toString () de este objeto y salga "200";
• En la línea 5, Integer100+INT100 obtendrá un tipo de datos básico B1 de tipo int y valor 200. La operación == Unboxes Long200 para obtener B2. Obviamente B1 == B2, y sale verdadero;
• En la línea 6, Integer100+INT100 obtendrá un tipo de datos básico de tipo B de tipo int y valor 200. Long's Ecals Method Boxs B, pero el boxeo da como resultado objeto O de tipo entero, porque O y Long200 son objetos de diferentes tipos, por lo que la salida es falsa;
El resultado del programa en ejecución es:
200
verdadero
FALSO
Por lo tanto, la segunda especulación es correcta, es decir, la clase de encapsulación se unirá durante la operación +.
trampa
Trampa 1
Entero entero100 = nulo;
int100 = Integer100;
Estas dos líneas de código son completamente legales y pueden compilarse por completo, pero cuando se ejecuta, se lanzará una excepción de puntero nulo. Entre ellos, Integer100 es un objeto de tipo entero, que por supuesto puede señalar a NULL. Pero en la segunda línea, Integer100 se unbogará, es decir, el método intValue () se ejecutará en un objeto nulo y, por supuesto, se lanzará una excepción de puntero nulo. Por lo tanto, al desempaquetar, debe prestar especial atención a si el objeto de clase encapsulado es nulo.
Trampa
Entero i1 = 100;
Entero i2 = 100;
Entero i3 = 300;
Entero i4 = 300;
System.out.println (i1 == i2);
System.out.println (i3 == i4);
Debido a que I1, I2, I3 e I4 son todos tipos enteros, creemos que los resultados de la ejecución deberían ser falsos. Sin embargo, el resultado de ejecución real es "System.out.println (i1 == i2);" Lo cual es cierto, pero "System.out.println (i3 == i4);" que es falso. Esto significa que las referencias de los dos tipos enteros, I1 e I2, apuntan al mismo objeto, mientras que I3 e I4, apuntan a diferentes objetos. ¿Por qué? ¿No son todos llamados el método entero.valueof (int i)?
Echemos un vistazo al entero.valueof (int i) el método nuevamente.
/** * Devuelve una instancia <tt> entero </tt> que representa el valor especificado * <tt> int </tt>. * Si no se requiere una nueva instancia <tt> Integer </tt>, este método * generalmente debe usarse en preferencia al constructor * {@link #Integer (int)}, ya que es probable que este método produzca * rendimiento de tiempo significativamente mejor al almacenarse en caché * los valores solicitados frecuentemente. * * @param i an <code> int </code> valor. * @return a <tt> entero </tt> instancia que representa <tt> i </tt>. * @since 1.5 */ public static entero Value de (int i) {if (i> = -128 && i <= integerCache.high) return integerCache.cache [i + 128]; else devuelve nuevo entero (i); }Podemos ver que cuando i> =-128 e i <= integerCache.high, el integercache.cache [i + 128] se devuelve directamente. Entre ellos, IntegerCache es una clase estática interna de entero, y su código original es el siguiente:
Clase estática privada IntegerCache {static final int high; Cache entero final estático []; static {final int low = -128; // El alto valor puede ser configurado por la propiedad int h = 127; if (integerCacheHighPropvalue! = null) {// use long.Decode aquí para evitar invocar métodos que // requieren la memoria caché de autoboxing de Integer para inicializarse int i = long.Decode (IntegerCacheHighPropvalue) .intvalue (); i = math.max (i, 127); // El tamaño máximo de la matriz es integer.max_value h = math.min (i, integer.max_value - -low); } high = h; caché = nuevo entero [(alto - bajo) + 1]; int j = bajo; para (int k = 0; k <cache.length; k ++) caché [k] = nuevo entero (j ++); } private integerCache () {}}Podemos ver claramente que IntegerCache tiene un caché variable de miembro estático, que es una matriz con 256 elementos. El caché también se inicializa en IntegerCache, es decir, el elemento I-Th es un objeto entero con un valor de I-128. -128 a 127 son los objetos enteros más utilizados, y este enfoque también mejora en gran medida el rendimiento. También es por esto que "integeri1 = 100; entero i2 = 100;", i1 e i2 obtienen el mismo objeto.
Comparando el segundo experimento en la extensión, aprendimos que cuando la clase de encapsulación se está ejecutando == con el tipo básico, la clase de encapsulación se unbogará, y el resultado de unboxing se compara con el tipo básico; Mientras que cuando las dos clases de encapsulación se ejecutan == con los otros objetos, comparan las direcciones de los dos objetos, es decir, para determinar si las dos referencias apuntan al mismo objeto.
El artículo anterior discute brevemente el embalaje automático de Java y la unboxing y sus trampas es todo el contenido que comparto con usted. Espero que pueda darle una referencia y espero que pueda apoyar más a Wulin.com.