CodeGym/Blog Java/Random-ES/Clase Java.lang.Integer
John Squirrels
Nivel 41
San Francisco

Clase Java.lang.Integer

Publicado en el grupo Random-ES
Los tipos de datos Java se pueden dividir condicionalmente en dos bloques: primitivos y de referencia (clases). Hay varios tipos de datos primitivos en Java, como números enteros ( byte , short , int , long ), números de coma flotante ( float , double ), tipos de datos lógicos ( booleanos ) y tipos de datos de caracteres ( char ). Probablemente ya sepa que cada tipo de datos primitivo tiene su propia clase contenedora. Un tipo de datos de referencia que "envuelve" o convierte a su hermano pequeño primitivo en un objeto Java. Integer es una clase contenedora para su hermano primitivo llamado int. Entero en inglés significa un número entero. Pueden ser positivos, negativos o 0. Desafortunadamente, entero en Java no significa ningún número entero. Un entero en Java es un número entero que cabe en 32 bits. Si desea un número mayor, puede utilizar números largos de Java . Tienen 64 bits a su disposición. Si tiene la mala suerte de necesitar un número aún mayor, Java lo tiene cubierto con BigInteger .

Trabajar con números enteros

Como clase contenedora, Integer proporciona varios métodos para trabajar con int , así como varios métodos para convertir int en String y String en int . La clase tiene dos constructores:
  • public Integer(int i) , donde i es un valor primitivo para inicializar. Este crea un objeto Integer que se inicializa con el valor int .

  • public Integer(String s) lanza NumberFormatException . Aquí s es una representación de cadena del valor int . Este constructor crea un objeto Integer que se inicializó con el valor int proporcionado por la representación de cadena .

Creación de objetos enteros

Existen diferentes opciones de creación de objetos Integer . Uno de los más utilizados es el más sencillo. Aquí hay un ejemplo:
Integer myInteger = 5;
La inicialización de la variable Integer en este caso es similar a la inicialización de la variable int primitiva . Por cierto, puedes inicializar una variable Integer con el valor de un int . Aquí hay un ejemplo:
int myInt = 5;
Integer myInteger = myInt;
System.out.println(myInteger);
El resultado aquí es:
5
De hecho, aquí podemos observar el embalaje automático. También podemos crear un objeto Integer como cualquier otro objeto usando un constructor y una nueva palabra clave:
Integer myInteger = new Integer(5);
Puedes hacer con la variable Integer lo mismo que con int (suma, resta, multiplica, divide, incrementa, disminuye). Sin embargo, es importante recordar que Integer es un tipo de datos de referencia y una variable de este tipo puede ser nula. En este caso, es mejor abstenerse de realizar este tipo de operaciones.
Integer myInteger1  = null;
Integer myInteger2 = myInteger1 + 5;
Aquí obtendremos una excepción:
Excepción en el hilo "principal" java.lang.NullPointerException"

Constantes de clase entera

La clase Integer proporciona varias constantes y métodos para trabajar con números enteros. Aquí están:
  • TAMAÑO significa el número de bits en el sistema numérico de dos dígitos ocupados por el tipo int

  • BYTES es el número de bytes en un sistema numérico de dos dígitos ocupados por el tipo int

  • MAX_VALUE es el valor máximo que puede contener el tipo int

  • MIN_VALUE es el valor mínimo que puede contener el tipo int

  • TYPE devuelve un objeto de tipo Clase de tipo int

Métodos más útiles de clase entera

Ahora echemos un vistazo a los métodos más utilizados de la clase Integer . Supongo que los más populares son los métodos para convertir un número a partir de un String , o viceversa.
  • static int parseInt(String s) este método convierte String en int . Si la conversión no es posible, se lanzará NumberFormatException .

  • static int parseInt(String s, int radix) este método también convierte el parámetro s en un int . El parámetro de base indica que el sistema numérico se escribió originalmente.

Además de parseInt , también existe un método valueOf muy similar en varias variaciones. Sin embargo, el resultado de valueOf será Integer y parseInt será int .
  • static Integer valueOf(int i) devuelve un entero cuyo valor es i ;

  • static Integer valueOf(String s) funciona como parseInt(String s) , pero el resultado será Integer , no int ;

  • static Integer valueOf(String s, int radix) funciona igual que parseInt(String s, int radix) , pero el resultado es un Integer , no un int .

¿Hay algún problema con la clase Integer? Ah, sí, hay...

Entonces, hay dos tipos de números enteros (que caben en 32 bits) en Java: int e Integer . Para comprender los detalles de cada uno de ellos, necesitamos saber lo siguiente sobre el modelo de memoria JVM: todo lo que declara se almacena en Stack Memory (pila JVM específica para cada subproceso) o en Heap Space. Los tipos primitivos ( int , long , float , boolean , double , char , byte , etc.) se almacenan en la memoria de pila. Todos los objetos y matrices se almacenan en Heap Space. Las referencias a estos objetos y las matrices necesarias para los métodos se almacenan en Stack. Entonces. ¿Por qué nos importa? Bueno, verá, Stack es más pequeño que Heap (una desventaja), pero es mucho más rápido asignar valores en Stack que en Heap (una ventaja). Comencemos con un tipo primitivo int . Ocupa exactamente 32 bits. Eso es 32/8=4 bytes. Porque es un tipo primitivo. Ahora, consideremos el número entero . Es un objeto, con gastos generales y alineaciones adicionales. He usado un jol de biblioteca para medir su tamaño:
public static void main(String[] args) {
 	System.out.println(ClassLayout.parseInstance(Integer.valueOf(1)).toPrintable());
}
y resultó ocupar 16 bytes:
componentes internos del objeto java.lang.Integer: OFF SZ TIPO DESCRIPCIÓN VALOR 0 8 (encabezado del objeto: marca) 0x000000748c90e301 (hash: 0x748c90e3; edad: 0) 8 4 (encabezado del objeto: clase) 0x000492a0 12 4 int Integer.value 1 Tamaño de instancia: 16 bytes
¡¿Qué?! ¡Eso es 4 veces más memoria! Pero no nos quedemos ahí. Como desarrolladores de Java normalmente no dejamos de utilizar un único número entero. Lo que realmente queremos es utilizar muchos de ellos. Como en una secuencia. Por ejemplo, en una matriz. O una lista. Las matrices se almacenan en el montón, al igual que las listas. Por lo tanto, la asignación debería llevar aproximadamente la misma cantidad de tiempo. ¿Bien? Pero ¿qué pasa si necesitamos asignar más memoria? Comprobemos cuánto espacio ocupa una matriz de 1000 valores int primitivos:
public static void main(String[] args) {
    	int[] array = new int[1000];
    	for (int i = 0; i < 1000; i++) array[i] = i;                System.out.println(ClassLayout.parseInstance(array).toPrintable());
}
Y el resultado es 4016 bytes:
OFF SZ TIPO DESCRIPCIÓN VALOR 0 8 (encabezado del objeto: marca) 0x00000000000000001 (no polarizable; edad: 0) 8 4 (encabezado del objeto: clase) 0x00006c38 12 4 (longitud de la matriz) 1000 12 4 (alineación/espacio de relleno) 16 4000 int [I.<elementos> N/A Tamaño de instancia: 4016 bytes Pérdidas de espacio: 4 bytes internos + 0 bytes externos = 4 bytes en total
Bien, eso tiene sentido, considerando que un solo int ocupa 4 bytes. ¿Qué pasa con un ArrayList<Integer> de 1000 enteros ? Echemos un vistazo:
public static void main(String[] args) {
	List<Integer> list = new ArrayList<>(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
      System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
Y el resultado es 20040 bytes (¡nuevamente, 4 veces más!):
java.util.ArrayList@66d3c617d huella: CUENTA PROMEDIO SUMA DESCRIPCIÓN 1 4016 4016 [Ljava.lang.Object; 1000 16 16000 java.lang.Integer 1 24 24 java.util.ArrayList 1002 20040 (total)
Entonces, ArrayList<Integer> ocupa 4 veces más espacio de memoria. Eso no es bueno. Pero aún así, ¡las listas son más fáciles porque podemos agregar y eliminar elementos! Oh Java… ¿Por qué necesitas empaquetar todo? Pero se me olvida que Java es fantástico y su grandeza reside en la abundancia de bibliotecas de código abierto que podemos utilizar. Trove4j es uno de ellos. Tiene TIntArrayList que internamente tiene datos int[] . Midamos su tamaño:
public static void main(String[] args) {
	TIntList list = new TIntArrayList(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	System.out.println(GraphLayout.parseInstance(list).toFootprint());
}
Y el resultado es 4040 bytes (¡casi lo mismo que int[] !):
gnu.trove.list.array.TIntArrayList@7440e464d huella: RECUENTO PROMEDIO SUMA DESCRIPCIÓN 1 4016 4016 [I 1 24 24 gnu.trove.list.array.TIntArrayList 2 4040 (total)
Entonces, al final, ¡podemos tener lo mejor de ambos mundos! Listas de números enteros que ocupan 4 veces menos espacio. Y esto no involucra instancias enteras . Sólo int s. A los desarrolladores de Java realmente nos preocupamos por la memoria... Pero también nos preocupamos por el rendimiento. Existe una maravillosa biblioteca de microbenchmarking con un nombre modesto jmh que nos permite medir el rendimiento del código. Primero, comparemos el rendimiento del cálculo de una suma de dos números enteros aleatorios, encuadrados o no: La configuración para jmh es la siguiente:
benchmark {
	configurations {
    	main {
        	warmups = 5 // number of warmup iterations
        	iterations = 50 // number of iterations
        	iterationTime = 500 // time in seconds per iteration
        	iterationTimeUnit = "ns" // time unit for iterationTime
Los puntos de referencia:
private static final Random random = new Random();

@Benchmark
public int testPrimitiveIntegersSum() {
	int a = random.nextInt();
	int b = random.nextInt();
	return a + b;
}

@Benchmark
public Integer testBoxedIntegersSum() {
	Integer a = random.nextInt();
	Integer b = random.nextInt();
	return a + b;
}
Los resultados:
principal: test.SampleJavaBenchmark.testBoxedIntegersSum 5693337.344 ±(99.9%) 1198774.178 operaciones/s [Promedio] (min, avg, max) = (1092314.989, 5693337.344, 12001683.428), stdev = 242158 3,144 IC (99,9%): [4494563,166, 6892111,522] (asume distribución normal) principal: test.SampleJavaBenchmark.testPrimitiveIntegersSum 15295010.959 ±(99.9%) 2555447.456 ops/s [Promedio] (min, avg, max) = (4560097.059, 15295010.959, 24283809.447), st desarrollo = 5162130,283 IC (99,9%): [12739563.502, 17850458.415] (se supone una distribución normal)
Entonces, en promedio, la asignación y la suma de enteros primitivos es más del doble de rápida que la de los enteros encajonados. Ahora, comparemos el rendimiento de la creación y el cálculo de la suma de colecciones (o matrices de 1000 enteros):
@Benchmark
public int testPrimitiveArray() {
	int[] array = new int[1000];
	for (int i = 0; i < 1000; i++) array[i] = i;
	int sum = 0;
	for (int x : array) sum += x;
	return sum;
}
11933.545 ops/s [Average]


@Benchmark
public int testBoxesArray() {
	Integer[] array = new Integer[1000];
	for (int i = 0; i < 1000; i++) array[i] = i;
	int sum = 0;
	for (int x : array) sum += x;
	return sum;
}
2733.312 ops/s [Average]


@Benchmark
public int testList() {
	List<Integer> list = new ArrayList<>(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	int sum = 0;
	for (int x : list) sum += x;
	return sum;
}
2086.379 ops/s [Average]


@Benchmark
public int testTroveIntList() {
	TIntList list = new TIntArrayList(1000);
	for (int i = 0; i < 1000; i++) list.add(i);
	int sum = 0;
	for (int i = 0; i < 1000; i++) sum += list.get(i);
	return sum;
}
5727.979 ops/s [Average]
Los resultados: la matriz de primitivas es más de 4 veces más rápida que la matriz de valores en cuadros ( Integer s); casi seis veces más rápido que ArrayList de valores en cuadros ( Integer s); y dos veces más rápido que TIntArrayList (que en realidad decora una serie de entradas primitivas). Por lo tanto, si necesita una estructura de datos para almacenar una colección de valores enteros y su tamaño no va a cambiar, use un int[] ; Si el tamaño va a cambiar, es posible que desee utilizar la biblioteca tove4j con TIntArrayList . Y aquí llega el final de mi ensayo donde explico las desventajas de usar el tipo Integer . Hay algunos métodos estáticos interesantes de Integer , de los que debería hablar antes de terminar. public static Integer getInteger(String nm, int val) no hace lo que uno podría pensar, pero recupera un valor entero de una propiedad del sistema. Val es el valor predeterminado en caso de que esta propiedad no esté configurada. public static String toBinaryString(int i) devuelve una cadena con una representación binaria de un número. Existen métodos para recuperar representaciones basadas en 16 ( toHexString ) y basadas en 8 ( toOctalString ). Existe un método para analizar una cadena en un int . Incluso si la cadena es una representación basada en 10 bases. A continuación se muestran algunos ejemplos: Integer.parseInt("-FF", 16) devuelve -255 Integer.parseInt("+42", 10) devuelve 42 Integer.parseInt("1100110", 2) devuelve 102
Comentarios
  • Populares
  • Nuevas
  • Antiguas
Debes iniciar sesión para dejar un comentario
Esta página aún no tiene comentarios