metodos - libreria toolkit java
Java: ¿Por qué son necesarias las clases de contenedor? (11)
Al igual que la clase String, los Wrappers proporcionan funcionalidad adicional y permiten al programador hacer un poco más con el proceso de almacenamiento de datos. Entonces, de la misma manera que la gente usa la clase String como ....
String uglyString = "fUbAr"; String myStr = uglyString.toLower();
también lo pueden hacer con Wrapper. Idea similar
Esto se suma a la cuestión de tipeo de colecciones / genéricos mencionados anteriormente por Bharat.
En el muy alto nivel, sé que tenemos que "ajustar" los tipos de datos primitivos, como int y char, utilizando sus respectivas clases contenedoras para usarlos dentro de las colecciones Java. Me gustaría entender cómo funcionan las colecciones Java en el nivel bajo preguntando: "¿por qué tenemos que envolver los tipos de datos primitivos como objetos para poder usarlos en las colecciones?" Le agradezco de antemano su ayuda.
Bueno, la razón es porque las colecciones de Java no diferencian entre primitivo y Objeto. Los procesa todos como Objeto y, por lo tanto, necesitará un contenedor. Puedes construir fácilmente tu propia clase de colección que no necesita envoltorio, pero al final, tendrás que compilar una para cada tipo char, int, float, double, etc. multiplica por los tipos de colecciones (Set, Map, Lista, + su implementación).
¿Te imaginas lo aburrido que es eso?
Y el hecho es que el rendimiento que trae al usar sin envoltorio es casi insignificante para la mayoría de las aplicaciones. Sin embargo, si necesita un rendimiento muy alto, algunas bibliotecas para colecciones primitivas también están disponibles (por ejemplo, http://www.joda.org/joda-primitives/ )
Colección utiliza genéricos como las bases. The Collection Framework está diseñado para recopilar, almacenar y manipular los datos de cualquier clase. Entonces usa un tipo genérico. Al usar Generics, es capaz de almacenar los datos de CUALQUIER CLASE cuyo nombre especifique en su declaración.
Ahora tenemos varios escenarios en los que queremos almacenar los datos primitivos de la misma manera en que funciona la colección. No tenemos forma de almacenar datos primitivos usando clases de Colección como ArrayList, HashSet, etc. porque las clases de Colección solo pueden almacenar objetos. Entonces, para almacenar tipos primitivos en Collection, se nos proporcionan clases de contenedor.
Debido a que las colecciones de Java solo pueden almacenar Referencias de objetos (por lo que debe colocar primitivas en el cuadro para almacenarlas en colecciones).
Lea este breve artículo sobre Autoboxing para obtener más información.
Si desea los detalles esenciales, se reduce a lo siguiente:
Los primitivos locales se almacenan en la pila. Las colecciones almacenan sus valores a través de una referencia a la ubicación de memoria de un Objeto en el Heap. Para obtener esa referencia para una primitiva local, tiene que insertar el valor (tomar el valor en la pila y envolverlo para almacenarlo en el montón).
En el nivel de la máquina virtual, se debe a que los tipos primitivos se representan de forma muy diferente en la memoria en comparación con los tipos de referencia, como java.lang.Object y sus tipos derivados. Primitive int en Java, por ejemplo, tiene solo 4 bytes en la memoria, mientras que un objeto ocupa al menos 8 bytes por sí mismo, más otros 4 bytes para hacer referencia a él. Tal diseño es un simple reflejo del hecho de que las CPU pueden tratar tipos primitivos de manera mucho más eficiente.
Entonces, una respuesta a su pregunta "por qué se necesitan tipos de envoltura" se debe a la mejora del rendimiento que permite.
Pero para los programadores, tal distinción agrega una sobrecarga cognitiva indeseable (por ejemplo, no se puede usar int y float en las colecciones). De hecho, es bastante posible hacer un diseño de lenguaje ocultando esa distinción --- muchos lenguajes de scripting hacen esto, y CLR hace eso. A partir de 1.5, Java también lo hace. Esto se logra al permitir que el compilador inserte silenciosamente la conversión necesaria entre la representación primitiva y la representación del objeto (que comúnmente se conoce como boxeo / unboxing).
Entonces, otra respuesta a su pregunta es: "no, no la necesitamos", porque el compilador lo hace automáticamente por usted y, en cierta medida, puede olvidar lo que ocurre detrás de la escena.
Las clases Wrapper proporcionan métodos útiles relacionados con los tipos de datos correspondientes que puede utilizar en ciertos casos.
Un simple ejemplo. Considera esto,
Integer x=new Integer(10);
//to get the byte value of 10
x.byteValue();
//but you can''t do this,
int x=10;
x.byteValue(); //Wrong!
puedes entender el punto?
Lea todas las respuestas, pero ninguna de ellas realmente lo explica simplemente en términos sencillos.
Una clase contenedora envuelve (encierra) alrededor de un tipo de datos (puede ser cualquier tipo de datos primitivos como int, char, byte, long) y lo convierte en un objeto .
Aquí hay algunas razones por las que se necesitan clases de contenedor:
- Permite valores
null
- Se puede usar en colecciones como
List
,Map
, etc. - Se puede usar en métodos que aceptan argumentos de tipo
Object
. Se puede crear como Objetos usando
new ClassName()
como otros objetos:Integer wrapperInt = new Integer("10");
- Hace disponibles todas las funciones que tiene la clase
Object
, comoclone()
,equals()
,hashCode()
,toString()
etc.
Las clases de contenedor se pueden crear de dos maneras:
Usando constructor:
Integer i = new Integer("1"); //new object is created
Usando
valueOf()
operadores estáticos:Integer i = Integer.valueOf("100"); //100 is stored in variable
Se recomienda utilizar la segunda forma de crear clases contenedoras, ya que requiere menos memoria ya que no se crea un objeto nuevo.
Los tipos de datos primitivos no se pueden referenciar como direcciones de memoria. Es por eso que necesitamos envolturas que sirvan como marcadores de posición para valores primitivos. Estos valores pueden ser mutados y accedidos, reorganizados, ordenados o aleatorizados.
Para almacenar los valores de tipo primitivo en las clases de recopilación, requerimos classe Wrapper.
Si se sabe que una variable contiene un patrón de bits específico que representa null
o información que se puede usar para localizar un encabezado de objeto Java Virtual Machine, y si el método para leer un encabezado de objeto dado una referencia se atrapará si se le da el patrón de bits asociado con null
, entonces la JVM puede acceder al objeto identificado por la variable en el supuesto de que exista uno. Si una variable puede contener algo que no era una referencia válida pero que no era el patrón de bits null
específico, cualquier código que intentara usar esa variable tendría que verificar primero si identificaba un objeto. Eso ralentizaría mucho la JVM.
Si Object
deriva de Anything
y los objetos de clase derivados de Object
, pero primitivos heredados de una clase diferente derivada de Anything
, entonces en una implementación de 64 bits podría ser práctico decir que aproximadamente 3/4 de los posibles patrones de bits representarían el double
valores por debajo de 2 ^ 512, 1/8 de ellos para representar valores long
en el rango +/- 1,152,921,504,606,846,975, algunos miles de millones para representar cualquier valor posible de cualquier primitve y 1/256 para identificar objetos. Muchos tipos de operaciones en cosas de tipo Anything
sería más lenta que con Object
tipo, pero tales operaciones no serían terriblemente frecuentes; la mayoría del código terminaría convirtiendo Anything
en algún tipo más específico antes de intentar trabajar con él; el tipo real almacenado en Anything
necesitaría ser revisado antes del lanzamiento, pero no después de que se realizó el lanzamiento. Sin una distinción entre una variable que contiene una referencia a un tipo de montón, sin embargo, frente a una que tenga "nada", no habría forma de evitar que la sobrecarga se extienda considerablemente más allá de lo que debería o debería.
Ver boxeo y unboxing: ¿cuándo aparece?
Es para C #, pero el mismo concepto se aplica a Java. Y John Skeet escribió la respuesta.