Constructor en Java

Constructor en Java se utiliza para crear la instancia de la clase. Los constructores son casi similares a los métodos, excepto por dos cosas: su nombre es el mismo que el nombre de la clase y no tiene un tipo de retorno. A veces, los constructores también se conocen como métodos especiales para inicializar un objeto.

Constructor en Java

Cuando usamos la palabra clave new para crear una instancia de una clase, se invoca al constructor y se devuelve el objeto de la clase. Dado que el constructor solo puede devolver el objeto a la clase, esto se hace implícitamente por el tiempo de ejecución de Java y no debemos agregarle un tipo de retorno. Si agregamos un tipo de retorno a un constructor, entonces se convertirá en un método de la clase. De esta manera, el tiempo de ejecución de Java distingue entre un método normal y un constructor. Supongamos que tenemos el siguiente código en la clase Empleado.

public Employee() {
	System.out.println("Employee Constructor");
}


public Employee Employee() {
	System.out.println("Employee Method");
	return new Employee();
}

Aquí, el primero es un constructor; observe que no hay un tipo de retorno y no hay una declaración de retorno. El segundo es un método normal en el que nuevamente llamamos al primer constructor para obtener una instancia de Empleado y devolverla. Se recomienda no tener el mismo nombre de método que el nombre de la clase porque esto crea confusión.

Tipos de Constructores en Java

Hay tres tipos de constructores en Java.

  1. Constructor predeterminado
  2. Constructor sin argumentos
  3. Constructor parametrizado

Vamos a examinar todos estos tipos de constructores con programas de ejemplo.

Constructor predeterminado en Java

No es necesario proporcionar siempre una implementación de constructor en el código de la clase. Si no proporcionamos un constructor, entonces Java proporciona una implementación de constructor predeterminada para que la usemos. Veamos un programa simple donde se está utilizando el constructor predeterminado ya que no definiremos explícitamente un constructor.

package com.journaldev.constructor;

public class Data {

	public static void main(String[] args) {
		Data d = new Data();
	}
}
  1. El único papel del constructor predeterminado es inicializar el objeto y devolverlo al código que lo llama.
  2. El constructor predeterminado siempre está sin argumentos y es proporcionado por el compilador de Java solo cuando no hay un constructor existente definido.
  3. La mayor parte del tiempo estamos bien con el constructor predeterminado en sí, ya que otras propiedades pueden ser accedidas e inicializadas a través de los métodos getter setter.

Constructor sin argumentos

El constructor sin ningún argumento se llama constructor sin argumentos. Es como anular el constructor predeterminado y se utiliza para realizar algunas tareas de preinicialización, como verificar recursos, conexiones de red, registro, etc. Echemos un vistazo rápido al constructor sin argumentos en Java.

package com.journaldev.constructor;

public class Data {
        //constructor sin argumentos
	public Data() {
		System.out.println("No-Args Constructor");
	}
	public static void main(String[] args) {
		Data d = new Data();
	}
}

Ahora, cuando llamemos a new Data(), se llamará a nuestro constructor sin argumentos. La siguiente imagen ilustra este comportamiento, verifica la salida en la consola del programa.

Constructor con parámetros

El constructor con argumentos se llama constructor con parámetros. Veamos un ejemplo de constructor con parámetros en Java.

package com.journaldev.constructor;

public class Data {

	private String name;

	public Data(String n) {
		System.out.println("Parameterized Constructor");
		this.name = n;
	}

	public String getName() {
		return name;
	}

	public static void main(String[] args) {
		Data d = new Data("Java");
		System.out.println(d.getName());
	}

}

Sobrecarga de constructores en Java

Cuando tenemos más de un constructor, entonces es una sobrecarga de constructores en Java. Veamos un ejemplo de sobrecarga de constructores en un programa Java.

package com.journaldev.constructor;

public class Data {

	private String name;
	private int id;

	//constructor sin argumentos
	public Data() {
		this.name = "Default Name";
	}
	//constructor con un parámetro
	public Data(String n) {
		this.name = n;
	}
	//constructor con dos parámetros
	public Data(String n, int i) {
		this.name = n;
		this.id = i;
	}

	public String getName() {
		return name;
	}

	public int getId() {
		return id;
	}

	@Override
	public String toString() {
		return "ID="+id+", Name="+name;
	}
	public static void main(String[] args) {
		Data d = new Data();
		System.out.println(d);
		
		d = new Data("Java");
		System.out.println(d);
		
		d = new Data("Pankaj", 25);
		System.out.println(d);
		
	}

}

Constructor Privado en Java

Ten en cuenta que no podemos usar las palabras clave abstract, final, static y synchronized con constructores. Sin embargo, podemos usar modificadores de acceso para controlar la instanciación del objeto de clase. El uso de public y default sigue siendo válido, pero ¿cuál es el uso de hacer un constructor privado? En ese caso, cualquier otra clase no podrá crear la instancia de la clase. Bueno, se hace un constructor privado en caso de que queramos implementar el patrón de diseño singleton. Dado que Java proporciona automáticamente un constructor predeterminado, debemos crear explícitamente un constructor y mantenerlo privado. Las clases de cliente se proporcionan con un método estático de utilidad para obtener la instancia de la clase. A continuación se muestra un ejemplo de constructor privado para la clase Data.

// constructor privado
private Data() {
	// constructor vacío para la implementación del patrón singleton
	// puede contener código para ser utilizado dentro del método getInstance() de la clase
}

Encadenamiento de constructores en Java

Cuando un constructor llama a otro constructor de la misma clase, se le llama encadenamiento de constructores. Tenemos que usar la palabra clave this para llamar a otro constructor de la clase. A veces se utiliza para establecer algunos valores predeterminados de las variables de clase. Ten en cuenta que otra llamada al constructor debe ser la primera instrucción en el bloque de código. Además, no debe haber llamadas recursivas que creen un bucle infinito. Veamos un ejemplo de encadenamiento de constructores en un programa Java.

package com.journaldev.constructor;

public class Employee {

	private int id;
	private String name;
	
	public Employee() {
		this("John Doe", 999);
		System.out.println("Default Employee Created");
	}
	
	public Employee(int i) {
		this("John Doe", i);
		System.out.println("Employee Created with Default Name");
	}
	public Employee(String s, int i) {
		this.id = i;
		this.name = s;
		System.out.println("Employee Created");
	}
	public static void main(String[] args) {

		Employee emp = new Employee();
		System.out.println(emp);
		Employee emp1 = new Employee(10);
		System.out.println(emp1);
		Employee emp2 = new Employee("Pankaj", 20);
		System.out.println(emp2);
	}

	@Override
	public String toString() {
		return "ID = "+id+", Name = "+name;
	}
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

I have overridden the toString() method to print some useful information about Employee object. Below is the output produced by above program.

Employee Created
Default Employee Created
ID = 999, Name = John Doe
Employee Created
Employee Created with Default Name
ID = 10, Name = John Doe
Employee Created
ID = 20, Name = Pankaj

Observa cómo se llama a un constructor desde otro constructor, eso se llama proceso de encadenamiento de constructores.

Constructor Super en Java

A veces una clase hereda de una superclase, en ese caso, si tenemos que llamar al constructor de la superclase, podemos hacerlo usando la palabra clave super. Veamos un ejemplo de cómo usar el constructor de la superclase. Tenga en cuenta que la llamada al constructor super debe ser la primera instrucción en el constructor de la clase hija. Además, al instanciar el constructor de la clase hija, Java primero inicializa la superclase y luego la clase hija. Por lo tanto, si el constructor de la superclase no se llama explícitamente, entonces el constructor predeterminado o sin argumentos es llamado por el tiempo de ejecución de Java. Entendamos estos conceptos a través de un programa de ejemplo. Supongamos que tenemos dos clases como se muestra a continuación.

package com.journaldev.constructor;

public class Person {

	private int age;

	public Person() {
		System.out.println("Person Created");
	}

	public Person(int i) {
		this.age = i;
		System.out.println("Person Created with Age = " + i);
	}

}
package com.journaldev.constructor;

public class Student extends Person {

	private String name;

	public Student() {
		System.out.println("Student Created");
	}

	public Student(int i, String n) {
		super(i); // super class constructor called
		this.name = n;
		System.out.println("Student Created with name = " + n);
	}

}

Ahora, si creamos un objeto Estudiante como se muestra a continuación;

Student st = new Student();

¿Cuál será el resultado producido? El resultado del código anterior será:

Person Created
Student Created

Entonces, la llamada fue al constructor sin argumentos de la clase Estudiante ya que no había una llamada a super en la primera instrucción, se llama al constructor predeterminado o sin argumentos de la clase Persona. Por lo tanto, el resultado. ¿Qué pasa si estamos usando el constructor parametrizado de la clase Estudiante como Student st = new Student(34, "Pankaj");, el resultado será:

Person Created with Age = 34
Student Created with name = Pankaj

Aquí el resultado es claro porque estamos llamando explícitamente al constructor de la superclase, así que Java no necesita hacer ningún trabajo adicional desde su lado.

Constructor de Copia en Java

El constructor de copia de Java toma el objeto de la misma clase como argumento y crea una copia de él. A veces necesitamos una copia de otro objeto para realizar algún procesamiento. Podemos hacer esto de las siguientes maneras:

  1. implementar clonación
  2. proporcionar un método de utilidad para copia profunda del objeto.
  3. Tener un constructor de copia

Ahora veamos cómo escribir un constructor de copia. Supongamos que tenemos una clase Fruits como se muestra a continuación.

package com.journaldev.constructor;

import java.util.ArrayList;
import java.util.List;

public class Fruits {

	private List<String> fruitsList;

	public List<String> getFruitsList() {
		return fruitsList;
	}

	public void setFruitsList(List<String> fruitsList) {
		this.fruitsList = fruitsList;
	}

	public Fruits(List<String> fl) {
		this.fruitsList = fl;
	}
	
	public Fruits(Fruits fr) {
		List<String> fl = new ArrayList<>();
		for (String f : fr.getFruitsList()) {
			fl.add(f);
		}
		this.fruitsList = fl;
	}
}

Observa que Fruits(Fruits fr) realiza una copia profunda para devolver la copia del objeto. Veamos un programa de prueba para entender por qué es mejor tener un constructor de copia para copiar un objeto.

package com.journaldev.constructor;

import java.util.ArrayList;
import java.util.List;

public class CopyConstructorTest {

	public static void main(String[] args) {
		List<String> fl = new ArrayList<>();
		fl.add("Mango");
		fl.add("Orange");

		Fruits fr = new Fruits(fl);

		System.out.println(fr.getFruitsList());

		Fruits frCopy = fr;
		frCopy.getFruitsList().add("Apple");

		System.out.println(fr.getFruitsList());

		frCopy = new Fruits(fr);
		frCopy.getFruitsList().add("Banana");
		System.out.println(fr.getFruitsList());
		System.out.println(frCopy.getFruitsList());

	}

}

La salida del programa anterior es:

[Mango, Orange]
[Mango, Orange, Apple]
[Mango, Orange, Apple]
[Mango, Orange, Apple, Banana]

Observa que cuando se usa el constructor de copia, tanto el objeto original como su copia no están relacionados entre sí y cualquier modificación en uno de ellos no se reflejará en el otro. Eso es todo para el constructor en Java.

Source:
https://www.digitalocean.com/community/tutorials/constructor-in-java