<h2>Introducción</h2>Un lenguaje de programación, como el lenguaje que habla la gente, vive y cambia, aparecen nuevos fenómenos en él para hacer que el lenguaje sea más cómodo de usar. Y como sabemos, el lenguaje debe expresar convenientemente nuestros pensamientos.
Entonces, en Java SE 5, se introdujo el mecanismo de boxeo/unboxing. Y un tutorial separado de Oracle está dedicado a las características de este medio para expresar pensamientos: Autoboxing y Unboxing . <h2>Boxeo de empaque automático</h2>Veamos un ejemplo de Boxeo de empaque automático. Primero, veamos cómo funciona. Usemos el sitio compilejava.net y creemos una clase:
Este es el mismo notorio "código de bytes". Pero lo que es importante para nosotros ahora es lo que vemos. Primero, la primitiva 8080 se coloca en la pila de ejecución del método y luego se ejecuta Integer.valueOf . Ésta es la “magia” del boxeo. Y por dentro la magia se ve así:
Es decir, en esencia, se tomará
Como puedes ver, no hay magia. Todo está dentro de Java. Simplemente funciona "por sí solo". Para nuestra comodidad. <h2>Rastrillo</h2>
Cualquier herramienta, si se utiliza incorrectamente, se convierte en un arma formidable contra sí misma. Y el mecanismo automático de boxeo/unboxing en Java no es una excepción. La primera comparación obvia es a través de
public class App {
public static void main(String[] args) {
Integer portNumber = 8080;
if (args.length != 0) {
portNumber = Integer.valueOf(args[0]);
}
System.out.println("Port number is: " + portNumber);
}
}
Código sencillo. Podemos especificar el parámetro de entrada y cambiar el valor del puerto. Como vemos, porque leemos el valor del puerto de String
los parámetros, Integer
lo obtenemos al pasarlo Integer.valueOf
. Por lo tanto, nos vemos obligados a especificarlo no como un tipo primitivo, sino como un tipo de objeto Integer
. Y aquí tenemos, por un lado, que tenemos una variable de objeto y el valor predeterminado es una primitiva. Y funciona. Pero no creemos en la magia, ¿verdad? Echemos un vistazo "debajo del capó", como dicen. Descargue el código fuente de compilejava.net haciendo clic en "Descargar ZIP". Después de eso, extraiga el archivo descargado en un directorio y acceda a él. Ahora hagamos: javap -c -p App.class
donde App.class es el archivo de clase compilado para su clase. Veremos contenidos como este:
Integer
o se obtendrá uno nuevo Integer
del caché (el caché no es más que una simple matriz de números enteros) dependiendo del valor del número. Naturalmente, Integer
no sólo uno tuvo tanta suerte. Hay una lista completa de tipos primitivos relacionados y sus envoltorios (clases que representan primitivos en el mundo de la programación orientada a objetos). Esta lista se encuentra al final del Tutorial de Oracle: " Autoboxing y Unboxing ". Vale la pena señalar de inmediato que las matrices creadas a partir de primitivos no tienen un "envoltorio" sin conectar bibliotecas de terceros. Aquellos. Arrays.asList
no hará de int[]
para nosotros List
de Integer
's. <h2>Unboxing</h2>El proceso inverso al boxeo se llama unboxing unboxing. Veamos un ejemplo de desembalaje:
public class App {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Please, enter params");
return;
}
int value = Math.abs(Integer.valueOf(args[0]));
System.out.println("Absolute value is: " + value);
}
}
Math.abs
sólo acepta primitivas. ¿Qué hacer? La clase contenedora tiene un método especial para este caso que devuelve una primitiva. Por ejemplo, este es el Integer
método intValue . Si miramos el código de bytes, es así:
==
. Creo que esto está claro, pero veámoslo de nuevo:
public static void main(String[] args) {
Integer inCacheValue = 127;
Integer inCacheValue2 = 127;
Integer notInCache = 128; // new Integer(129)
Integer notInCache2 = 128; // new Integer(129)
System.out.println(inCacheValue == inCacheValue2); //true
System.out.println(notInCache == notInCache2); //false
}
En el primer caso, el valor se toma del Integer
caché de valores (ver explicación de Boxing arriba), y en el segundo caso se creará un nuevo objeto cada vez. Pero aquí vale la pena hacer una reserva. Este comportamiento depende del límite superior de la caché ( java.lang.Integer.IntegerCache.high ). Además, este límite puede cambiar debido a otras configuraciones. Puede leer la discusión sobre este tema en stackoverflow: ¿ Qué tamaño tiene la caché de enteros? Naturalmente, los objetos deben compararse utilizando iguales: System.out.println(notInCache.equals(notInCache2));
el segundo problema asociado con el mismo mecanismo es el rendimiento. Cualquier boxeo en Java equivale a crear un nuevo objeto. Si el número no está incluido en los valores de la caché (es decir, de -128 a 127), se creará un nuevo objeto cada vez. Si de repente el empaquetado (es decir, el empaquetado) se realiza en un bucle, esto provocará un enorme aumento de objetos innecesarios y el consumo de recursos para el trabajo del recolector de basura. Por lo tanto, no seas demasiado imprudente al respecto. Un tercer rastrillo, no menos doloroso, surge del mismo mecanismo:
public static void check(Integer value) {
if (value <= 0) {
throw new IllegalStateException("Value is too small");
}
}
En este código, la persona claramente intentaba no superar el error. Pero no hay ningún control para null
. Si se trata de la entrada null
, en lugar de un error comprensible obtendremos uno incomprensible NullPointerException
. Porque a modo de comparación, Java intentará ejecutarse value.intValue
y fallar, porque... value
voluntad null
. <h2>Conclusión</h2>El mecanismo de boxeo/unboxing permite al programador escribir menos código y, a veces, ni siquiera pensar en convertir de primitivos a objetos y viceversa. Pero eso no significa que debas olvidar cómo funciona. De lo contrario, puedes cometer un error que quizás no aparezca de inmediato. No debemos confiar en partes del sistema que no están completamente bajo nuestro control (como el límite de los enteros). Pero no te olvides de todas las ventajas de las clases contenedoras (como Integer
). A menudo, estas clases contenedoras tienen un conjunto de métodos estáticos adicionales que mejorarán su vida y su código será más expresivo. He aquí un ejemplo de puesta al día:
public static void main(String[] args) {
int first = 1;
int second = 5;
System.out.println(Integer.max(first, second));
System.out.println(Character.toLowerCase('S'));
}
La conclusión correcta de todo es que no hay magia, hay algún tipo de realización. Y no todo será siempre lo que esperamos. Por ejemplo, no hay empaquetado: System.out.println("The number is " + 8);
el compilador optimizará el ejemplo anterior en una línea. Es decir, es como si escribieras “El número es 8”. Y en el siguiente ejemplo tampoco habrá embalaje:
public static void main(String[] args) {
System.out.println("The number is " + Math.abs(-2));
}
¿Cómo puede ser cuando println
tomamos un objeto como entrada y necesitamos conectar las líneas de alguna manera? Líneas... sí, por eso no existe un packaging como tal. Existen Integer
métodos estáticos, pero algunos de ellos lo son package
. Es decir, no podemos usarlos, pero en el propio Java se pueden usar activamente. Este es exactamente el caso aquí. Se llamará al método getChars, que crea una matriz de caracteres a partir del número. Nuevamente, no hay magia, solo Java). Entonces, en cualquier situación poco clara, solo hay que observar la implementación y al menos algo encajará. #viacheslav
GO TO FULL VERSION