1. Información general
En pocas palabras, antes de que podamos trabajar con un objeto en la JVM, debe inicializarse.
En las siguientes secciones, veremos varias formas en las que podemos inicializar tipos y objetos primitivos.
2. Declaración vs. Inicialización
Comencemos asegurándonos de que estamos en la misma página.
La declaración es el proceso de definir la variable junto con su tipo y nombre.
Aquí, estamos declarando la variable id :
int id;
La inicialización, por otro lado, se trata de asignar un valor; por ejemplo:
id = 1;
Para demostrarlo, crearemos una clase de usuario con un nombre y propiedades de identificación :
public class User { private String name; private int id; // standard constructor, getters, setters, }
A continuación, veremos que la inicialización funciona de manera diferente según el tipo de campo que estamos inicializando.
3. Objetos frente a primitivos
Java proporciona dos tipos de representación de datos: tipos primitivos y tipos de referencia. En esta sección, discutiremos las diferencias entre los dos con respecto a la inicialización.
Java tiene ocho tipos de datos integrados, denominados tipos primitivos de Java; las variables de este tipo mantienen sus valores directamente.
Los tipos de referencia contienen referencias a objetos (instancias de clases). A diferencia de los tipos primitivos que mantienen sus valores en la memoria donde se asigna la variable, las referencias no contienen el valor del objeto al que se refieren.
En cambio, una referencia apunta a un objeto almacenando la dirección de memoria donde se encuentra el objeto.
Tenga en cuenta que Java no nos permite descubrir cuál es la dirección de memoria física. Más bien, solo podemos usar la referencia para referirnos al objeto.
Echemos un vistazo a un ejemplo que declara e inicializa un tipo de referencia fuera de nuestra clase de usuario :
@Test public void whenIntializedWithNew_thenInstanceIsNotNull() { User user = new User(); assertThat(user).isNotNull(); }
Como podemos ver aquí, se puede asignar una referencia a un nuevo usando la palabra clave new, que es responsable de crear el nuevo objeto Usuario .
Continuemos aprendiendo más sobre la creación de objetos.
5. Creando objetos
A diferencia de las primitivas, la creación de objetos es un poco más compleja. Esto se debe a que no solo estamos agregando el valor al campo; en su lugar, activamos la inicialización usando la nueva palabra clave. Esto, a cambio, invoca un constructor e inicializa el objeto en la memoria.
Analicemos los constructores y la nueva palabra clave con más detalle.
La nueva palabra clave es responsable de asignar memoria para el nuevo objeto a través de un constructor.
Normalmente, se utiliza un constructor para inicializar variables de instancia que representan las propiedades principales del objeto creado .
Si no proporcionamos un constructor explícitamente, el compilador creará un constructor predeterminado que no tiene argumentos y solo asigna memoria para el objeto.
Una clase puede tener muchos constructores siempre que sus listas de parámetros sean diferentes ( sobrecarga ) . Cada constructor que no llama a otro constructor en la misma clase tiene una llamada a su constructor padre, ya sea que haya sido escrito explícitamente o insertado por el compilador a través de super () .
Agreguemos un constructor a nuestra clase de usuario :
public User(String name, int id) { this.name = name; this.id = id; }
Ahora podemos usar nuestro constructor para crear un objeto Usuario con valores iniciales para sus propiedades:
User user = new User("Alice", 1);
6. Alcance variable
En las siguientes secciones, veremos los diferentes tipos de ámbitos en los que puede existir una variable en Java y cómo esto afecta el proceso de inicialización.
6.1. Variables de instancia y clase
Las variables de instancia y clase no requieren que las inicialicemos. Tan pronto como declaramos estas variables, se les asigna un valor predeterminado de la siguiente manera:

Ahora, intentemos definir algunas variables relacionadas con la instancia y la clase y probar si tienen un valor predeterminado o no:
@Test public void whenValuesAreNotInitialized_thenUserNameAndIdReturnDefault() { User user = new User(); assertThat(user.getName()).isNull(); assertThat(user.getId() == 0); }
6.2. Variables locales
Las variables locales deben inicializarse antes de su uso , ya que no tienen un valor predeterminado y el compilador no nos permitirá usar un valor no inicializado.
Por ejemplo, el siguiente código genera un error del compilador:
public void print(){ int i; System.out.println(i); }
7. La palabra clave final
La palabra clave final aplicada a un campo significa que el valor del campo ya no se puede cambiar después de la inicialización. De esta forma, podemos definir constantes en Java.
Let's add a constant to our User class:
private static final int YEAR = 2000;
Constants must be initialized either when they're declared or in a constructor.
8. Initializers in Java
In Java, an initializer is a block of code that has no associated name or data type and is placed outside of any method, constructor, or another block of code.
Java offers two types of initializers, static and instance initializers. Let's see how we can use each of them.
8.1. Instance Initializers
We can use these to initialize instance variables.
To demonstrate, let’s provide a value for a user id using an instance initializer in our User class:
{ id = 0; }
8.2. Static Initialization Block
A static initializer or static block – is a block of code which is used to initialize static fields. In other words, it’s a simple initializer marked with the keyword static:
private static String forum; static { forum = "Java"; }
9. Order of Initialization
When writing code that initializes different types of fields, of course, we have to keep an eye on the order of initialization.
In Java, the order for initialization statements is as follows:
- static variables and static initializers in order
- instance variables and instance initializers in order
- constructors
10. Object Life Cycle
Now that we've learned how to declare and initialize objects, let's discover what happens to objects when they're not in use.
Unlike other languages where we have to worry about object destruction, Java takes care of obsolete objects through its garbage collector.
All objects in Java are stored in our program's heap memory. In fact, the heap represents a large pool of unused memory, allocated for our Java application.
On the other hand, the garbage collector is a Java program that takes care of automatic memory management by deleting objects that are no longer reachable.
For a Java object to become unreachable, it has to encounter one of the following situations:
- The object no longer has any references pointing to it
- All reference pointing to the object are out of scope
In conclusion, an object is first created from a class, usually using the keyword new. Then the object lives its life and provides us with access to its methods and fields.
Finally, when it's no longer needed, the garbage collector destroys it.
11. Other Methods for Creating Objects
In this section, we’ll take a brief look at methods other than new keyword to create objects and how to apply them, specifically reflection, cloning, and serialization.
Reflection is a mechanism we can use to inspect classes, fields, and methods at run-time. Here's an example of creating our User object using reflection:
@Test public void whenInitializedWithReflection_thenInstanceIsNotNull() throws Exception { User user = User.class.getConstructor(String.class, int.class) .newInstance("Alice", 2); assertThat(user).isNotNull(); }
In this case, we're using reflection to find and invoke a constructor of the User class.
The next method, cloning, is a way to create an exact copy of an object. For this, our User class must implement the Cloneable interface:
public class User implements Cloneable { //... }
Ahora podemos usar el método clone () para crear un nuevo objeto clonedUser que tiene los mismos valores de propiedad que el objeto de usuario :
@Test public void whenCopiedWithClone_thenExactMatchIsCreated() throws CloneNotSupportedException { User user = new User("Alice", 3); User clonedUser = (User) user.clone(); assertThat(clonedUser).isEqualTo(user); }
También podemos usar la clase sun.misc.Unsafe para asignar memoria para un objeto sin llamar a un constructor:
User u = (User) unsafeInstance.allocateInstance(User.class);
12. Conclusión
En este tutorial, cubrimos la inicialización de campos en Java. Descubrimos diferentes tipos de datos en Java y cómo usarlos. También analizamos en profundidad varias formas de crear objetos en Java.
La implementación completa de este tutorial se puede encontrar en Github.