Поиск по сайту:

Конструктор на Java


Конструктор в java используется для создания экземпляра класса. Конструкторы почти аналогичны методам, за исключением двух вещей: их имя такое же, как имя класса, и у них нет возвращаемого типа. Иногда конструкторы также называют специальными методами для инициализации объекта.

Конструктор на Java

Всякий раз, когда мы используем ключевое слово new для создания экземпляра класса, вызывается конструктор и возвращается объект класса. Поскольку конструктор может возвращать объект только классу, это неявно выполняется средой выполнения Java, и мы не должны добавлять к нему возвращаемый тип. Если мы добавим возвращаемый тип в конструктор, то он станет методом класса. Именно так среда выполнения Java различает обычный метод и конструктор. Предположим, у нас есть следующий код в классе Employee.

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


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

Здесь первым является конструктор, обратите внимание, что здесь нет возвращаемого типа и оператора возврата. Второй — это обычный метод, в котором мы снова вызываем первый конструктор, чтобы получить экземпляр Employee и вернуть его. Рекомендуется, чтобы имя метода не совпадало с именем класса, потому что это создает путаницу.

Типы конструктора в Java

В java есть три типа конструкторов.

  1. Конструктор по умолчанию
  2. Конструктор без аргументов
  3. Конструктор с параметрами

Давайте рассмотрим все эти типы конструкторов на примерах программ.

Конструктор по умолчанию в Java

Не обязательно всегда предоставлять реализацию конструктора в коде класса. Если мы не предоставляем конструктор, то java предоставляет нам реализацию конструктора по умолчанию. Давайте рассмотрим простую программу, в которой используется конструктор по умолчанию, поскольку мы не будем явно определять конструктор.

package com.journaldev.constructor;

public class Data {

	public static void main(String[] args) {
		Data d = new Data();
	}
}

  1. Единственная роль конструктора по умолчанию — инициализировать объект и вернуть его вызывающему коду.
  2. Конструктор по умолчанию всегда без аргументов и предоставляется компилятором Java только в том случае, если существующий конструктор не определен.
  3. Большую часть времени нас устраивает сам конструктор по умолчанию, поскольку доступ к другим свойствам и их инициализация можно получить с помощью методов установки-получателя.

Конструктор без аргументов

Конструктор без аргументов называется конструктором без аргументов. Это похоже на переопределение конструктора по умолчанию и его использование для выполнения некоторых действий перед инициализацией, таких как проверка ресурсов, сетевых подключений, ведение журнала и т. д. Давайте кратко рассмотрим конструктор без аргументов в java.

package com.journaldev.constructor;

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

Параметризованный конструктор

Конструктор с аргументами называется параметризованным конструктором. Давайте посмотрим на пример параметризованного конструктора в 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());
	}

}

Перегрузка конструктора в Java

Когда у нас есть более одного конструктора, это перегрузка конструктора в java. Давайте рассмотрим пример перегрузки конструктора в java-программе.

package com.journaldev.constructor;

public class Data {

	private String name;
	private int id;

	//no-args constructor
	public Data() {
		this.name = "Default Name";
	}
	//one parameter constructor
	public Data(String n) {
		this.name = n;
	}
	//two parameter constructor
	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);
		
	}

}

Частный конструктор в Java

Обратите внимание, что мы не можем использовать шаблон проектирования singleton. Поскольку Java автоматически предоставляет конструктор по умолчанию, мы должны явно создать конструктор и сохранить его закрытым. Клиентские классы снабжены служебным статическим методом для получения экземпляра класса. Пример приватного конструктора для класса Data приведен ниже.

// private constructor
private Data() {
	//empty constructor for singleton pattern implementation
	//can have code to be used inside the getInstance() method of class
}

Цепочка конструкторов в Java

Когда конструктор вызывает другой конструктор того же класса, это называется цепочкой конструкторов. Мы должны использовать ключевое слово this для вызова другого конструктора класса. Иногда он используется для установки некоторых значений по умолчанию для переменных класса. Обратите внимание, что вызов другого конструктора должен быть первым оператором в блоке кода. Также не должно быть рекурсивных вызовов, которые создадут бесконечный цикл. Давайте посмотрим на пример цепочки конструкторов в 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;
	}

}

Я переопределил метод toString(), чтобы вывести некоторую полезную информацию об объекте Employee. Ниже приведен вывод, полученный с помощью вышеуказанной программы.

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

Обратите внимание, как один конструктор вызывается из другого конструктора, это называется процессом связывания конструкторов.

Суперконструктор Java

Иногда класс наследуется от суперкласса, в этом случае, если нам нужно вызвать конструктор суперкласса, мы можем сделать это с помощью ключевого слова super. Давайте посмотрим на пример использования конструктора суперкласса. Обратите внимание, что вызов суперконструктора должен быть первым оператором в конструкторе дочернего класса. Также при создании экземпляра конструктора дочернего класса java сначала инициализирует суперкласс, а затем дочерний класс. Поэтому, если конструктор суперкласса не вызывается явно, тогда среда выполнения java вызывает конструктор по умолчанию или конструктор без аргументов. Давайте разберемся с этими концепциями на примере какой-нибудь программы. Предположим, у нас есть два класса, как показано ниже.

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);
	}

}

Теперь, если мы создадим объект Student, как показано ниже;

Student st = new Student();

Что будет произведено на выходе? Вывод приведенного выше кода будет:

Person Created
Student Created

Таким образом, вызов перешел к конструктору без аргументов класса Student, поскольку в первом операторе не было супервызова, вызывается конструктор без аргументов или конструктор по умолчанию класса Person. Отсюда и выход. Что, если мы используем параметризованный конструктор класса Student как Student st=new Student(34, Pankaj);, результат будет таким:

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

Здесь вывод ясен, потому что мы явно вызываем конструктор суперкласса, поэтому Java не нужно выполнять какую-либо дополнительную работу со своей стороны.

Конструктор копирования Java

Конструктор копирования Java принимает объект того же класса в качестве аргумента и создает его копию. Иногда нам нужна копия другого объекта для некоторой обработки. Мы можем сделать это следующими способами:

  1. внедрить клонирование
  2. предоставление служебного метода для глубокого копирования объекта.
  3. Наличие конструктора копирования

Теперь давайте посмотрим, как написать конструктор копирования. Предположим, у нас есть класс Fruits, как показано ниже.

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;
	}
}

Обратите внимание, что Fruits(Fruits fr) выполняет глубокое копирование, чтобы вернуть копию объекта. Давайте посмотрим на тестовую программу, чтобы понять, почему лучше иметь конструктор копирования для копирования объекта.

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());

	}

}

Вывод вышеуказанной программы:

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

Обратите внимание, что при использовании конструктора копирования как исходный объект, так и его копия не связаны друг с другом, и любые изменения в одном из них не отразятся на другом. Это все, что касается конструктора в java.