Конструктор в 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 существуют три типа конструкторов.
- Конструктор по умолчанию
- Конструктор без аргументов
- Параметризированный конструктор
Давайте рассмотрим все эти типы конструкторов на примере программ.
Конструктор по умолчанию в Java
Не всегда требуется предоставлять реализацию конструктора в коде класса. Если мы не предоставляем конструктор, то Java предоставляет реализацию конструктора по умолчанию, которую мы можем использовать. Давайте рассмотрим простую программу, где используется конструктор по умолчанию, так как мы явно не определяем конструктор.
package com.journaldev.constructor;
public class Data {
public static void main(String[] args) {
Data d = new Data();
}
}
- Роль конструктора по умолчанию заключается только в инициализации объекта и его возврате вызывающему коду.
- Конструктор по умолчанию всегда без аргументов и предоставляется компилятором Java только в том случае, если не определен существующий конструктор.
- В большинстве случаев мы довольны только конструктором по умолчанию, так как другие свойства могут быть доступны и инициализированы через методы получения и установки значений.
Конструктор без аргументов
Конструктор без аргументов называется конструктором без аргументов. Это похоже на переопределение конструктора по умолчанию и используется для выполнения предварительной инициализации, такой как проверка ресурсов, сетевые подключения, ведение журнала и т. д. Давайте быстро рассмотрим конструктор без аргументов в Java.
package com.journaldev.constructor;
public class Data {
//конструктор без аргументов
public Data() {
System.out.println("No-Args Constructor");
}
public static void main(String[] args) {
Data d = new Data();
}
}
Теперь, когда мы вызовем 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;
//конструктор без аргументов
public Data() {
this.name = "Default Name";
}
//конструктор с одним параметром
public Data(String n) {
this.name = n;
}
//конструктор с двумя параметрами
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
Обратите внимание, что мы не можем использовать ключевые слова abstract, final, static и synchronized с конструкторами. Однако мы можем использовать модификаторы доступа для контроля над созданием объекта класса. Использование public
и default
доступа все еще допустимо, но для чего нужно делать конструктор приватным? В этом случае ни один другой класс не сможет создать экземпляр этого класса. В общем, конструктор делается приватным, если мы хотим реализовать шаблон проектирования Singleton. Поскольку Java автоматически предоставляет конструктор по умолчанию, мы должны явно создать конструктор и сделать его приватным. Клиентским классам предоставляется утилитарный статический метод для получения экземпляра класса. Ниже приведен пример приватного конструктора для класса Data
.
// приватный конструктор
private Data() {
// пустой конструктор для реализации шаблона Singleton
// может содержать код, используемый внутри метода getInstance() класса
}
Цепочка конструкторов в 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;
}
}
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
Обратите внимание, как один конструктор вызывается из другого конструктора, это называется процессом цепочки конструкторов.
Java Super Constructor
Иногда класс наследуется от суперкласса, в этом случае, если нам нужно вызвать конструктор суперкласса, мы можем сделать это с помощью ключевого слова 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
Так как в первом операторе нет вызова super, вызывается конструктор без аргументов или по умолчанию класса Student. Вот почему выводится данное значение. Что, если мы используем параметризованный конструктор класса Student, например Student st = new Student(34, "Pankaj");
? Результатом будет:
Person Created with Age = 34
Student Created with name = Pankaj
Здесь результат очевиден, так как мы явно вызываем конструктор суперкласса, Java не требуется выполнять никаких дополнительных действий.
Копирующий конструктор Java
Конструктор копирования в Java принимает объект того же класса в качестве аргумента и создает его копию. Иногда нам нужна копия другого объекта для выполнения некоторой обработки. Мы можем сделать это следующими способами:
- реализация клонирования
- предоставление утилитного метода для глубокого копирования объекта.
- Иметь конструктор копирования
Теперь давайте посмотрим, как написать конструктор копирования. Предположим, у нас есть класс 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.
Source:
https://www.digitalocean.com/community/tutorials/constructor-in-java