Prefacio
Este artículo presenta principalmente contenido relevante sobre Integer en Java, y lo comparte para su referencia y aprendizaje. No diré mucho a continuación, echemos un vistazo a la introducción detallada juntos.
Parásitos reales
Hace unos días, vi un artículo compartido por mis momentos "El mecanismo de transmisión de parámetros de las funciones de Java: ¿realmente lo entiendes?》
Algunos desencadenantes se han estudiado en el entero de Java antes, así que escribí este artículo, con la esperanza de que te sea útil.
intercambio
Primero veamos un ejemplo.
Utilice Java para completar la función de intercambio e intercambiar valores de dos tipos enteros.
public static void test () lanza la excepción {Integer a = 1, b = 2; intercambio (a, b); System.out.println ("a =" + a + ", b =" + b);} swap natic void (entero a, entero b) {// partes que deben implementarse} primero
Si no comprende cómo se asignan los objetos Java en la memoria y cómo los métodos pasan los parámetros, puede escribir el siguiente código.
public static void swapone (entero a, entero b) arroja excepción {Integer ateMpValue = a; a = b; b = atempvalue;} Los resultados de la ejecución muestran que los valores A y B no se intercambian.
Así que echemos un vistazo a cómo se asignan los objetos Java en la memoria cuando se ejecuta el programa anterior:
Asignación de dirección de objeto
De esto podemos ver que las tablas variables locales de los dos métodos tienen referencias a las direcciones de datos reales de los objetos A y B.
La función de intercambio implementada anteriormente solo intercambia referencias a la variable local A y la variable local B en la función de intercambio, y no intercambia los datos reales en el montón JVM.
Por lo tanto, los datos mencionados por A y B en la función principal no se intercambian, por lo que la A y B de las variables locales en la función principal no cambiarán.
Entonces, ¿cómo operas al intercambiar los datos en la función principal?
La segunda vez
Según la práctica anterior, ¿podemos considerar el intercambio de valores de datos de A y B en el montón JVM?
Aprendamos brevemente sobre el objeto entero. Solo tiene un valor de tipo INT de nivel de objeto para representar el valor del objeto.
Por lo tanto, usamos la reflexión para modificar el valor, el código es el siguiente:
public static void swaptwo (Integer A1, Integer B1) lanza la excepción {Field valuefield = integer.class.getDeclaredField ("valor"); vallefield.setAccessible (verdadero); int tempavalue = valuefield.getInt (a1); vallefield.setInt (a1, b1.intvalue ()); vallefield.setInt (B1, tempavalue);}Los resultados de la operación están en línea con las expectativas.
sorpresa
Después de ejecutar el programa anterior, ¿qué sucederá si declaro un Integer c = 1, d = 2;
El programa de muestra es el siguiente:
public static void swaptwo (Integer A1, Integer B1) lanza la excepción {Field valuefield = integer.class.getDeclaredField ("valor"); vallefield.setAccessible (verdadero); int tempavalue = valuefield.getInt (a1); vallefield.setInt (a1, b1.intvalue ()); vallefield.setInt (b1, tempavalue);} public static void testThree () lanza la excepción {Integer a = 1, b = 2; swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Entero C = 1, d = 2; System.out.println ("c =" + c + "; d =" + d);}Los resultados de la salida son los siguientes:
a = 2; b = 1c = 2; d = 1
¡Sorpresa o no! Accidente o no! Estimulando o no!
En profundidad
¿Qué pasó exactamente? Echemos un vistazo al código descompilado:
El autor usó la herramienta IDE para descompilar directamente este archivo .class
public static void testThree () lanza la excepción {Integer a = Integer.ValueOf (1); Entero b = entero.valueOf (2); swaptwo (a, b); System.out.println ("a =" + a + "; b =" + b); Entero c = integer.valueOf (1); Entero d = integer.valueOf (2); System.out.println ("c =" + c + "; d =" + d);} En el proceso de Java, boxeo automáticamente el tipo original int en el tipo entero Integer.valueOf(int) método.
Debe ser que este método encapsula algunas operaciones internamente, lo que nos hace tener un impacto global después de modificar Integer.value .
Todo esto implica que el código en esta parte del código se pegue a la vez (PS: el autor que no arrastra es un buen codificador):
Public Class Integer { / ** * @since 1.5 * / public static entero valorof (int i) {if (i> = integerCache.low && i <= integerCache.high) return integerCache.cache [i + (-intgerCache.low)]; devolver nuevo entero (i); } Clase estática privada IntegerCache {static final int low = -128; estático final int high; Cache entero final estático []; static {// El valor alto puede configurarse mediante la propiedad int h = 127; String IntegerCacheHighPropValue = Sun.Misc.Vm.GetSavedProperty ("java.lang.integer.integercache.high"); if (integerCacheHighPropValue! = null) {try {int i = parseInt (integerCacheHighPropValue); 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) -1); } Catch (NumberFormateException nfe) {// Si la propiedad no se puede analizar en un int, ignórelo. }} high = h; caché = nuevo entero [(alto - bajo) + 1]; int j = bajo; para (int k = 0; k <cache.length; k ++) caché [k] = nuevo entero (j ++); // El rango [-128, 127] debe ser internado (JLS7 5.1.7) Afirmar integerCache.high> = 127; } private integerCache () {}} Como se muestra arriba, Integer tiene un IntegerCache de clase estática privada en el interior, que inicializa estáticamente una matriz entera que contiene Integer.IntegerCache.low a java.lang.Integer.IntegerCache.high .
El rango de valor de java.lang.Integer.IntegerCache.high está entre [127~Integer.MAX_VALUE - (-low) -1] .
Todos los objetos devueltos por la función Integer.valueOf(int) en este intervalo se calculan según el valor INT y se obtienen de la matriz Integer.IntegerCache.cache . El objeto es el mismo y no se crea ningún objeto nuevo.
Entonces, cuando modificamos el valor de Integer.valueOf(1) , se cambiarán todos los valores de retorno de Integer.IntegerCache.cache[ 1 - IntegerCache.low ] .
Creo que tu coeficiente intelectual debería entenderse. Si no lo entiende, llame al 10086 en la sección de comentarios.
Ok, entonces, ¿qué pasa con la parte que no está en [IntegerCache.low~IntegerCache.high) ?
Obviamente, tienen suerte, no almacenados en caché por IntegerCache, y cada vez que llegan, asignarán un pedazo de tierra (de tierra adentro) (distribución) en el JVM.
Ensueño
¿Qué pasa si cambio el parámetro convertido a tipo a int?
public static void testone () lanza la excepción {int a = 1, b = 2; swapone (a, b); System.out.println ("a =" + a + ", b =" + b);} static void swapone (int a, int b) {// partes que deben implementarse} Con las habilidades actuales del autor, no hay solución. Los expertos pueden dejar mensajes en la cuenta oficial, ¡muchas gracias!
Hasta ahora, la parte de intercambio ha terminado.
1 + 1
Primero veamos el código:
public static void testone () {int One = 1; int dos = uno + uno; System.out.printf ("two =%d", dos);} ¿Cuál es la salida?
Si dice 2 para estar seguro, entonces lo ha aprendido en vano, llame al 95169 directamente.
Puedo decirle con certeza que puede ser cualquier valor en el intervalo [Integer.MIN_VALUE~Integer.MAX_VALUE] .
¡Sorpresa o no! Accidente o no! Estimulando o no!
Aprendemos el código de asado uno por uno.
El autor usó la herramienta IDE para descompilar directamente este archivo .class
public static void testone () {int One = 1; int dos = uno + uno; System.out.printf ("two =%d", dos);} La variable dos aquí no llamó a teger.valueOf(int) , que es diferente de lo que imaginé. Sospecho que esta es la olla de IDE.
Así que verifique el bytecode compilado decisivamente. Los siguientes son algunos de los bytecodes del extracto:
Ldc "two =%d" iconst_1anewarray java/lang/objectDupiConst_0iload 2invokestatic java/lang/integer.valueof (i) ljava/lang/integer; aastoreinvokevirtual java/io/printstream.printf (Ljava/lang/string; [ljava/lang/object;) ljava/io/printstream; pop
Se puede ver que de hecho es la olla del ide. No solo se llama Integer.valueOf(int) una vez, sino que también se crea una matriz de objeto.
El código Java completo debería verse así:
public static void testone () {int One = 1; int dos = uno + uno; Objeto [] params = {integer.valueOf (dos)}; System.out.printf ("two =%d", params);} Por lo tanto, simplemente modifique el valor de Integer.IntegerCache.cache[2+128] antes de que se llame el método, así que agregue algún código a la parte de inicialización estática de la clase.
public class OnePlusone {static {try {class <?> CacheClazz = class.forname ("java.lang.integer $ IntegerCache"); Campo Cachefield = CacheClazz.GetDeclaredField ("Cache"); cachefield.setAccessible (verdadero); Entero [] cache = (entero []) cachefield.get (null); // cambia aquí a 1 + 1 = 3 caché [2 + 128] = nuevo entero (3); } catch (Exception e) {E.PrintStackTrace (); }} public static void testone () {int uno = 1; int dos = uno + uno; System.out.printf ("two =%d", dos); }}dos == 2?
Después de modificar el valor de Integer.IntegerCache.cache[2 + 128] , ¿la variable dos es igual a 2?
public static void testTwo () {int One = 1; int dos = uno + uno; System.out.println (dos == 2); System.out.println (Integer.ValueOf (dos) == 2);}La salida del código anterior es la siguiente
verdadero
Debido a que dos == 2 no implica la conversión del boxeo entero, o una comparación del tipo original, el 2 del tipo original siempre es igual a 2.
La forma real de Integer.valueOf(two)==2 es Integer.valueOf(two).intValue == 2 , es decir, 3 == 2, por lo que es falso.
Aquí podemos ver que si compara un valor de NULL con una variable entera con una variable int con un signo doble igual, se lanzará una NullPointException.
¿Qué tipo de salida será si el método aquí es reemplazado por System.out.println("Two=" + two) ? Puedes probarlo.
posdata
Xcache
| amable | ¿Hay un caché? | Valor mínimo | Valor máximo |
|---|---|---|---|
| Booleano | ninguno | - | - |
| Byte | ByteCache | -128 | 127 (fijo) |
| Corto | Cortocacante | -128 | 127 (fijo) |
| Personaje | Carácter | 0 | 127 (fijo) |
| Entero | Integercache | -128 | java.lang.integer.integercache.high |
| Largo | Longcache | -128 | 127 (fijo) |
| Flotar | ninguno | - | - |
| Doble | ninguno | - | - |
java.lang.integer.integercache.high
Después de leer el método para obtener alto sun.misc.VM.getSavedProperty la clase IntegerCache, puede tener las siguientes preguntas. No nos retrasaremos y usaremos un método de una cuestión-una respuesta.
1. ¿Cómo pasar este valor al JVM?
Al igual que las propiedades del sistema, cuando se inicia JVM, se pasa configurando -Djava.lang.Integer.IntegerCache.high=xxx .
2. ¿Cuál es la diferencia entre este método y System.getProperty ?
Para distinguir los parámetros requeridos por el sistema JVM de los parámetros utilizados por el usuario,
Cuando se inicia java.lang.System.initializeSystemClass , los parámetros de inicio se guardarán en dos lugares:
2.1 Los parámetros del sistema recibidos por todos los JVM se guardan en Sun.misc.vm.SavedProps.
Cuando se inicia el JVM, llama al método java.lang.System.initializeSystemClass para inicializar la propiedad.
Al mismo tiempo, el método sun.misc.VM.saveAndRemoveProperties también se llamará para eliminar las siguientes propiedades de java.lang.System.props :
Las propiedades enumeradas anteriormente son todos los parámetros del sistema que deben establecerse para el inicio de JVM, por lo que para consideraciones de seguridad y consideraciones de aislamiento, separarlos del sistema accesible para el usuario.
2.2 Guardar otros parámetros, excepto los siguientes parámetros requeridos para el inicio JVM en java.lang.system.props.
PD: JDK 1.8.0_91 utilizado por el autor
IntegerCache para Java 9
Imagínese si el juego travieso anterior aparece en el paquete de dependencia de terceros, definitivamente habrá un grupo de programadores que se volverán locos (por favor no pruebe un juego tan malo, las consecuencias son muy graves).
Afortunadamente, Java 9 ha restringido esto. Puede escribir el archivo del módulo-Info.java en el módulo correspondiente, que restringe el uso de la reflexión para acceder a los miembros, etc. Después de la declaración según sea necesario, el código solo puede acceder a campos, métodos y otra información a la que se puede acceder mediante reflexión. Solo cuando la clase está en el mismo módulo, o el módulo ha abierto un paquete para el acceso a la reflexión. Para más detalles, consulte el artículo:
¿Modificar IntegerCache en Java 9?
Gracias a Lydia y Asuka por sus valiosos consejos y su arduo trabajo sobre la revisión.
Finalmente, me gustaría compartir con ustedes un problema que no presto atención al valor entero en Java:
Primero veamos un fragmento de código:
public static void main (string [] args) {integer a1 = integer.valueOf (60); // Danielinbiti Integer B1 = 60; System.out.println ("1: ="+(a1 == b1)); Entero a2 = 60; Entero b2 = 60; System.out.println ("2: ="+(a2 == b2)); Entero a3 = nuevo entero (60); Entero B3 = 60; System.out.println ("3: ="+(a3 == b3)); Entero a3 = nuevo entero (60); Entero B3 = 60; System.out.println ("3: ="+(a3 == b3)); Entero a4 = 129; Entero b4 = 129; System.out.println ("4: ="+(a4 == b4)); } Si el resultado de comparación de este código no se ejecuta, no sé cuáles son las respuestas en su mente.
Para conocer esta respuesta, involucra los problemas de búfer y almacenamiento de Java.
En Java, el tipo entero es un búfer para los números entre -128-127, por lo que es consistente con el signo igual. Pero para los números que no están en este rango, son nuevos en el montón. Por lo tanto, el espacio de direcciones es diferente, por lo que no es igual.
Integer b3=60 , este es un proceso de embalaje, es decir, Integer b3=Integer.valueOf(60)
Por lo tanto, en el futuro, cuando se encuentra con entero, debe usar intValue() para comparar si los valores son iguales.
No hay búfer para el doble.
Contestar
1: = verdadero
2: = verdadero
3: = falso
4: = falso
Resumir
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.