tipos tipo primitivos objeto ejemplos declaracion datos dato java primitive primitive-types autoboxing jdk1.5

objeto - ¿Por qué la gente todavía usa tipos primitivos en Java?



tipos de datos primitivos en java (19)

Desde Java 5, hemos tenido boxeo / unboxing de tipos primitivos para que int se ajuste para ser java.lang.Integer , y así sucesivamente.

Últimamente veo muchos proyectos nuevos de Java (que definitivamente requieren un JRE de al menos la versión 5, sino 6) que usan int lugar de java.lang.Integer , aunque es mucho más conveniente usar este último, ya que tiene algunos métodos auxiliares para convertir a valores long et al.

¿Por qué algunos todavía usan tipos primitivos en Java? ¿Hay algún beneficio tangible?


¿Puedes imaginar un

for (int i=0; i<10000; i++) { do something }

ciclo con java.lang.Integer en su lugar? Un java.lang.Integer es inmutable, por lo que cada incremento alrededor del ciclo crearía un nuevo objeto java en el montón, en lugar de simplemente incrementar el int en la pila con una sola instrucción JVM. El rendimiento sería diabólico.

Realmente no estoy de acuerdo con que sea mucho más conveniente usar java.lang.Integer que int. De lo contrario. Autoboxing significa que puedes usar int donde de otra manera estarías forzado a usar Integer, y el compilador java se encarga de insertar el código para crear el nuevo objeto Integer por ti. Autoboxing se trata de permitirle usar un int donde se espera un entero, con el compilador insertando la construcción del objeto relevante. De ninguna manera elimina o reduce la necesidad de int en primer lugar. Con el autoboxing obtienes lo mejor de ambos mundos. Obtienes un Entero creado automáticamente para ti cuando necesitas un objeto java basado en un montón, y obtienes la velocidad y eficiencia de un int cuando solo estás haciendo cálculos aritméticos y locales.


1) Necesita primitivas para realizar operaciones matemáticas 2) Primitivas requiere menos memoria como se respondió anteriormente y un mejor rendimiento

Debería preguntar por qué se requiere clase / tipo de objeto

La razón para tener el tipo de objeto es facilitarnos la vida cuando tratamos con colecciones. Los primitivos no se pueden agregar directamente a la Lista / Mapa, sino que es necesario escribir una clase contenedora. El tipo de clases enteras Readymade te ayuda aquí además de que tiene muchos métodos de utilidad como Integer.pareseInt (str)


Además de lo que otros han dicho, las variables locales primitivas no se asignan del montón, sino que se asignan a la pila. Pero los objetos se asignan desde el montón y, por lo tanto, tienen que ser recogidos.


Además de los problemas de rendimiento y memoria, me gustaría encontrar otro problema: la interfaz List se rompería sin int .
El problema es el método remove() sobrecargado ( remove(int) vs. remove(Object) ). remove(Integer) siempre resolvería llamar a este último, por lo que no podría eliminar un elemento por índice.

Por otro lado, hay una trampa al intentar agregar y eliminar un int :

final int i = 42; final List<Integer> list = new ArrayList<Integer>(); list.add(i); // add(Object) list.remove(i); // remove(int) - Ouch!


El autoenvasado puede conducir a NPE difíciles de detectar

Integer in = null; ... ... int i = in; // NPE at runtime

En la mayoría de las situaciones, la asignación nula a in es mucho menos obvia que la anterior.


En Java efectivo de Joshua Bloch, artículo 5: "Evita crear objetos innecesarios", publica el siguiente ejemplo de código:

public static void main(String[] args) { Long sum = 0L; // uses Long, not long for (long i = 0; i <= Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); }

y lleva 43 segundos correr. Tomando el Long en el primitivo lo reduce a 6.8 segundos ... Si eso es una indicación de por qué usamos primitivos.

La falta de igualdad de valores nativos también es una preocupación ( .equals() es bastante detallado en comparación con == )

para biziclop:

class Biziclop { public static void main(String[] args) { System.out.println(new Integer(5) == new Integer(5)); System.out.println(new Integer(500) == new Integer(500)); System.out.println(Integer.valueOf(5) == Integer.valueOf(5)); System.out.println(Integer.valueOf(500) == Integer.valueOf(500)); } }

Resultados en:

false false true false

EDITAR ¿Por qué (3) devuelve true y (4) devuelve false ?

Porque son dos objetos diferentes. Los 256 enteros más cercanos a cero [-128; 127] son ​​almacenados en caché por la JVM, por lo que devuelven el mismo objeto para esos. Más allá de ese rango, sin embargo, no están en la memoria caché, por lo que se crea un nuevo objeto. Para hacer las cosas más complicadas, JLS exige que se almacenen al menos 256 flyweights. Los implementadores de JVM pueden agregar más si lo desean, lo que significa que esto podría ejecutarse en un sistema donde los 1024 más cercanos se almacenan en caché y todos devuelven la verdad ... #awkward


En primer lugar, hábito. Si ha codificado en Java durante ocho años, acumulará una considerable cantidad de inercia. ¿Por qué cambiar si no hay una razón convincente para hacerlo? No es como si usar primitivas en caja tuviera ventajas adicionales.

La otra razón es afirmar que null no es una opción válida. Sería inútil y engañoso declarar la suma de dos números o una variable de bucle como Integer .

También está el aspecto de desempeño, mientras que la diferencia de rendimiento no es crítica en muchos casos (aunque cuando lo es, es bastante malo), a nadie le gusta escribir código que podría escribirse con la misma facilidad de una manera más rápida que ya estamos Acostumbrado a.


Es difícil saber qué tipo de optimizaciones están sucediendo bajo las sábanas.

Para uso local, cuando el compilador tiene suficiente información para realizar optimizaciones que excluyen la posibilidad del valor nulo, espero que el rendimiento sea el mismo o similar .

Sin embargo, las matrices de primitivas son aparentemente muy diferentes de las colecciones de primitivas en caja. Esto tiene sentido dado que muy pocas optimizaciones son posibles en lo profundo de una colección.

Además, Integer tiene una sobrecarga lógica mucho mayor en comparación con int : ahora tienes que preocuparte acerca de si int a = b + c; arroja una excepción.

Utilizaría las primitivas tanto como fuera posible y confiaría en los métodos de fábrica y en el autoboxing para darme los tipos de cajas más semánticamente potentes cuando los necesiten.


Estoy de acuerdo con las respuestas anteriores, el uso de primitivos objetos de envoltura puede ser costoso. Pero, si el rendimiento no es crítico en su aplicación, evitará desbordamientos al usar objetos. Por ejemplo:

long bigNumber = Integer.MAX_VALUE + 2;

El valor de bigNumber es -2147483647, y esperaría que fuera 2147483649. Se trata de un error en el código que se solucionaría haciendo:

long bigNumber = Integer.MAX_VALUE + 2l; // note that ''2'' is a long now.

Y bigNumber sería 2147483649. Este tipo de errores a veces son fáciles de perder y pueden llevar a comportamientos o vulnerabilidades desconocidos (ver CWE-190 ).

Si usa objetos wrapper, el código equivalente no se compilará.

Long bigNumber = Integer.MAX_VALUE + 2; // Not compiling

Por lo tanto, es más fácil detener este tipo de problemas mediante el uso de objetos envoltorios primitivos.

Su pregunta ya está respondida, que respondo solo para agregar un poco más de información no mencionada anteriormente.


Los objetos son mucho más pesados ​​que los tipos primitivos, por lo que los tipos primitivos son mucho más eficientes que las instancias de las clases contenedoras.

Los tipos primitivos son muy simples: por ejemplo, un int es de 32 bits y ocupa exactamente 32 bits en la memoria, y puede manipularse directamente. Un objeto entero es un objeto completo, que (como cualquier objeto) debe almacenarse en el montón, y solo se puede acceder a través de una referencia (puntero) a él. Lo más probable es que también ocupe más de 32 bits (4 bytes) de memoria.

Dicho esto, el hecho de que Java tenga una distinción entre tipos primitivos y no primitivos es también un signo de la antigüedad del lenguaje de programación Java. Los lenguajes de programación más nuevos no tienen esta distinción; el compilador de dicho lenguaje es lo suficientemente inteligente como para resolverlo solo si está utilizando valores simples u objetos más complejos.

Por ejemplo, en Scala no hay tipos primitivos; hay una clase Int para enteros, y un Int es un objeto real (que puede usar métodos, etc.). Cuando el compilador compila su código, utiliza datos primitivos detrás de la escena, por lo que usar un Int es tan eficiente como usar una primitiva int en Java.


Los tipos encuadrados tienen peor rendimiento y requieren más memoria.


Los tipos primitivos son mucho más rápidos:

int i; i++;

Entero (todos los números y también una cadena) es un tipo inmutable : una vez creado, no se puede cambiar. Si i fuera Integer, entonces i++ crearía un nuevo objeto Integer, mucho más costoso en términos de memoria y procesador.


Los tipos primitivos tienen muchas ventajas: - Código más simple de escribir - El rendimiento es mejor ya que no crea una instancia de un objeto para la variable - Dado que no representan una referencia a un objeto, no hay necesidad de verificar nulos - Use tipos primitivos a menos que necesita aprovechar las características del boxeo.


No puedo creer que nadie haya mencionado lo que creo que es la razón más importante: "int" es así, mucho más fácil de escribir que "Integer". Creo que las personas subestiman la importancia de una sintaxis concisa. El rendimiento no es realmente una razón para evitarlos porque la mayor parte del tiempo cuando uno usa números está en índices de bucle, y aumentarlos y compararlos no cuesta nada en ningún bucle no trivial (ya sea que esté utilizando int o Integer).

El otro motivo dado es que puede obtener NPE, pero eso es extremadamente fácil de evitar con tipos encuadrados (y se garantiza que se evitará siempre y cuando siempre los inicialice en valores no nulos).

La otra razón es que (nuevo Long (1000)) == (nuevo Long (1000)) es falso, pero eso es solo otra forma de decir que ".equals" no tiene soporte sintáctico para los tipos encuadrados (a diferencia de los operadores <,> , =, etc.), así que volvemos a la razón de la "sintaxis más simple".

Creo que el ejemplo de bucle no primitivo de Steve Yegge ilustra muy bien mi punto de vista: http://sites.google.com/site/steveyegge2/language-trickery-and-ejb

Piense en esto: con qué frecuencia utiliza tipos de funciones en lenguajes que tienen una buena sintaxis (como cualquier lenguaje funcional, python, ruby ​​e incluso C) en comparación con Java donde debe simularlos utilizando interfaces como Runnable y Callable y clases sin nombre.


Por cierto, Smalltalk solo tiene objetos (sin primitivas) y, sin embargo, optimizaron sus enteros pequeños (utilizando no todos los 32 bits, solo 27 o similares) para no asignar ningún espacio de montón, sino simplemente usar un patrón de bits especial. También otros objetos comunes (verdadero, falso, nulo) tenían patrones de bits especiales aquí.

Por lo tanto, al menos en las JVM de 64 bits (con un espacio de nombres de puntero de 64 bits) debería ser posible no tener ningún objeto de Integer, Character, Byte, Short, Boolean, Float (y Long Long) en absoluto (aparte de estos creados por new ...() explícitos new ...() ), solo patrones de bits especiales, que podrían ser manipulados por los operadores normales con bastante eficiencia.


Porque JAVA realiza todas las operaciones matemáticas en tipos primitivos. Considera este ejemplo:

public static int sumEven(List<Integer> li) { int sum = 0; for (Integer i: li) if (i % 2 == 0) sum += i; return sum; }

Aquí, las operaciones reminder y unary plus no se pueden aplicar en el tipo entero (referencia), el compilador realiza unboxing y realiza las operaciones.

Por lo tanto, asegúrese de cuántas operaciones de autoboxing y unboxing suceden en el programa Java. Dado que lleva tiempo realizar estas operaciones.

Generalmente, es mejor mantener argumentos de tipo Referencia y resultado de tipo primitivo.


Tipos primitivos:

int x = 1000; int y = 1000;

Ahora evalúa:

x == y

Es true Difícil de sorprender. Ahora prueba los tipos de caja:

Integer x = 1000; Integer y = 1000;

Ahora evalúa:

x == y

Es false Probablemente. Depende del tiempo de ejecución. ¿Es esa razón suficiente?


Un par de razones para no deshacerse de primitivos:

  • Compatibilidad hacia atrás.

Si se elimina, ningún programa anterior ni siquiera se ejecutará.

  • JVM reescribe

La JVM completa tendría que ser reescrita para soportar esta nueva cosa.

  • Mayor huella de memoria.

Necesitaría almacenar el valor y la referencia, que usa más memoria. Si tiene una gran variedad de bytes, usar byte es significativamente más pequeño que usar Byte .

  • Problemas con el puntero nulo.

Declarar int i luego hacer cosas no daría lugar a ningún problema, pero declarar Integer i y luego hacer lo mismo daría como resultado un NPE.

  • Problemas de igualdad.

Considera este código:

Integer i1 = 5; Integer i2 = 5; i1 == i2; // Currently would be false.

Sería falso Los operadores tendrían que estar sobrecargados, y eso daría como resultado una reescritura importante de cosas.

  • Lento

Los contenedores de objetos son significativamente más lentos que sus contrapartes primitivos.


int loops = 100000000; long start = System.currentTimeMillis(); for (Long l = new Long(0); l<loops;l++) { //System.out.println("Long: "+l); } System.out.println("Milliseconds taken to loop ''"+loops+"'' times around Long: "+ (System.currentTimeMillis()- start)); start = System.currentTimeMillis(); for (long l = 0; l<loops;l++) { //System.out.println("long: "+l); } System.out.println("Milliseconds taken to loop ''"+loops+"'' times around long: "+ (System.currentTimeMillis()- start));

Milisegundos tomados en bucle ''100000000'' veces en Long: 468

Milisegundos tomados en bucle ''100000000'' veces alrededor de largo: 31

En una nota lateral, no me importaría que algo como esto encuentre su camino hacia Java.

Integer loop1 = new Integer(0); for (loop1.lessThan(1000)) { ... }

Donde el bucle for aumenta automáticamente loop1 de 0 a 1000 o

Integer loop1 = new Integer(1000); for (loop1.greaterThan(0)) { ... }

Donde el bucle for automáticamente disminuye loop1 1000 a 0.