En esta entrada vamos a tener un breve resumen sobre lo mas importante que hemos dado sobre: Stack y Heap, Literales y Casting de Primitives, Ámbito de variables. Asignaciones básicas, Uso de una variable o un Elemento de un Array que está sin inicializar y sin asignar, Paso de variables en un método, Declaración de un Array, construcción e Inicialización, Bloques de Inicialización, Wrappers, Boxing, Sobrecarga Avanzada, Garbage Collector.
-
Stak y Heap
- Las variables locales (o variables de método) residen en el stack.
- Los objetos y sus variables de instancia residen en el heap.
-
Literales y Casting de Primitivos
- Los literales enteros pueden ser decimales, octales o hexadecimales.
- Los literales para longs terminan en L o l.
- Los literales Float terminan con F o f, y los literales double terminan con el dígito D o d.
- Los literales boolean son true o false.
- Los literales para chars son un caracter dentro de comillas simples: ‘d’.
-
Ámbito de variables
- El ámbito de una variable se refiere al tiempo de vida de una variable.
- Hay 4 ámbitos básicos:
- Variables Static viven básicamente tanto como la clase viva.
- Variables de instancia viven tanto como su objeto viva.
- Variables locales viven tanto como el método esté en el stack, sin embargo, si el método invoca otro método, no estará disponible temporalmente.
- Las variables de bloque viven hasta que el bloque se completa.
-
Asignaciones Básicas:
- Los literales enteros son implícitamente int.
- Las expresiones enteras siempre resultan en un resultado del tamaño de un int, nunca menor.
- Los números floating-point son implícitamente doubles (64 bits).
- Estrechar un primitivo trunca los bits de orden superior.
- Las asignaciones de composicion (+=, +=), realizan un cast automático.
- Una variable de referencia almacena los bits que son usados para referirse a un objeto.
- Las variables de referencia pueden referir a subclases del tipo declarado pero no a superclases.
- Cuando se crea un nuevo objeto, ocurren 3 cosas:
- Se crea una variable de referencia.
- Se crea el objeto.
- Se asigna el objeto a la variable de referencia.
-
Usar una variable o un Elemento de un Array que no ha sido inicializado ni asignado:
- Cuando un array de objetos es instanciado, los objetos dentro del array no son instanciados automáticamente, pero todas las referencias obtienen el valor por defecto null.
- Cuando un array de primitivos es instanciado, los elementos obtienen sus valores por defecto.
- Las variables de instancia son siempre inicializadas con el valor por defecto.
- Las variables locales o de método nunca obtienen valor por defecto. Si intentamos usar una antes de inicializarla, obtendremos un error de compilador.
-
Pasando variables a métodos
- Los métodos pueden coger primitivos y/o referencias a objetos como argumentos.
- Los argumentos de los métodos son siempre copias.
- Los argumentos de los métodos nunca son objetos actuales.
- Un argumento primitivo es una copia que no está ligada al primitivo original.
- Un argumento que es referencia a otra copia es una referencia al objeto original.
- Ocurre Shadowing cuando 2 variables con diferentes ámbitos de variable comparten el mismo nombre. Esto desemboca en bigs dificiles de encontrar.
-
Declaración de Array, Construcción e Inicialización
- Los arrays pueden almacenar primitivos u objetos, pero el array por sí mismo es un objeto.
- Cuando declaramos un array, los corchetes pueden estar a la izquierda o a al derecha del nombre.
- Nunca será legal incluir el tamaño de un array en la declaración.
- Se debe incluir el tamaño del array cuando lo construimos (usando new) a no ser que estemos creando un array anónimo.
- Los elementos de un array de objetos no son automáticamente creados, aunque en un array de elementos primitivos les es dado su valor por defecto.
- Obtendremos un NullPointerExceptiom si intentamos usar un array de elementos en un array de objetos, si el elemento no se refiere a un objeto real.
- El primer índice de un array comienza con 0.
- Un ArrayIndexOutOfBoundsException ocurre si usamos un valor erróneo como índice.
- Los arrays tienen una variable que nos indica su longitud la cual es la cantidad de elementos que tiene el array.
- El último índice al que podemos acceder es siempre la longitud del array menos uno.
- Los arrays multidimensionales son arrays de arrays.
- Las dimensiones de un array multidimensional pueden ser de diferentes longitudes.
- Un array de primitivos puede aceptar cualquier valor que pueda ser implícitamente promovido al tipo de array declarado.
- Un array de objetos puede almacenar cualquier objeto que pase el test IS-A para el tipo declarado del array.
- Si asignamos un array a una referencia de un array previamente declarada, el array que estamos asignando debe de tener la misma dimensión que el de la referencia al que la estamos asignando.
- Podemos asignar un array de un tipo a otroa referencia de array previamente declarada de su supertipo.
-
Bloques de Inicialización
- Los bloques de inicialización static solo se ejecutan uan vez, cuando la clase es por primera vez cargada.
- Los bloques de inicialización de instancia se ejecutan cada vez que una instancia nueva es creada. Se ejecutan después de todos los super-constructores se hayan ejecutado y antes de los constructores del código se hayan ejecutado.
- Si existen múltiples bloques de inicialización en una clase, se ejecutan según al regla que hemos visto en el punto anterior, y en el orden en el cual aparecen en el código fuente.
-
Wrappers
- Las clases Wrapper son correlativas a los tipos primitivos.
- Los Wrappers tienen 2 funciones:
- Envolver primitivos de manera que puedan ser tratados como objetos.
- Proveer métodos de utilidad para primitivos (normalmente conversiones).
- Las 3 familias de métodos mas importantes son:
- xxxValue() – No tiene argumentos, retorna un primitive.
- parseXxx() – String como argumento, retorna un primitivo, lanza NFE.
- valueOf() – String como argumento, retorna un objeto envuelto, lanza NFE.
- Los constructores de las Wrapper pueden tener un String o primitive como argumento, excepto para Character, que solo puede tener un char.
- Radix se refiere a las bases que no sean 10; octal es radix = 8, hex = 16.
-
Boxing
- El Boxing permite convertir primitivos a wrappers o convertir wrappers en primitivos automáticamente.
- Usar == con las wrappers creadas a través del boxing es dificil.
-
Sobrecarga Avanzada
- La ampliación de primitivos usa el método que tenga menor numero de argumentos posibles.
- Usado individualmente, el boxing y los var-args son compatibles con la sobrecarga.
- No podemos ampliar de un tipo wrapper a otro (IS-A falla).
- No podemos ampliar y entonces hacer box.
- Podemos hacer box y luego ampliar.
- Podemos combinar var-args con ampliación o boxing.
-
Garbage Collection:
- En Java, el GC provee una administración de memoria automática.
- El propósito del GC es eliminar objetos que ya no pueden ser alcanzados.
- Solo la JVM decide cuando ejecutar el GC, nosotros solo podemos sugerirlo.
- No podemos saber el algoritmo del GC por seguro.
- Los objetos deben ser considerados elegibles antes de que puedan ser recogidos por el GC.
- Un objeto es elegible cuando ningún thread con vida puede alcanzarlo.
- Para alcanzar un objeto, debemos tener una referencia viva y alcanzable a ese objeto.
- Una aplicación de Java puede quedarse sin memoria.
- Una isla de objetos puede ser GCed, incluso si se refieren unas a otras.
- Se puede requerir un GC con System.gc().
- La clase Object tiene el método finalize().
- El método finalize() nos garantiza que se ejecuta una vez y solo una antes de que el GC borre el objeto.
- El GC no ofrece garantias de que finalize() se ejecute.
- Podemos hacer que un objeto no sea elegible para el GC desde dentro del finalize().