웹사이트 검색

자바의 생성자


Java의 생성자는 클래스의 인스턴스를 만드는 데 사용됩니다. 생성자는 두 가지를 제외하고 메서드와 거의 유사합니다. 이름이 클래스 이름과 동일하고 반환 유형이 없습니다. 때때로 생성자는 개체를 초기화하는 특수 메서드라고도 합니다.

자바의 생성자

new 키워드를 사용하여 클래스의 인스턴스를 만들 때마다 생성자가 호출되고 클래스의 개체가 반환됩니다. 생성자는 클래스에 객체를 반환할 수만 있기 때문에 Java 런타임에 의해 암시적으로 수행되며 반환 유형을 추가해서는 안 됩니다. 생성자에 반환 유형을 추가하면 클래스의 메서드가 됩니다. 이것이 자바 런타임이 일반 메서드와 생성자를 구분하는 방식입니다. Employee 클래스에 다음 코드가 있다고 가정해 봅시다.

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


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

여기서 첫 번째는 생성자입니다. 반환 유형과 반환 문이 없다는 점에 유의하세요. 두 번째는 Employee 인스턴스를 가져오고 반환하기 위해 첫 번째 생성자를 다시 호출하는 일반 메서드입니다. 혼동을 일으키기 때문에 메서드 이름을 클래스 이름과 동일하게 지정하지 않는 것이 좋습니다.

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. 대부분의 경우 getter setter 메서드를 통해 다른 속성에 액세스하고 초기화할 수 있으므로 기본 생성자 자체로는 문제가 없습니다.

인수 없는 생성자

인수가 없는 생성자를 인수 없는 생성자라고 합니다. 이는 기본 생성자를 재정의하는 것과 같으며 리소스 확인, 네트워크 연결, 로깅 등과 같은 일부 사전 초기화 작업을 수행하는 데 사용됩니다. java의 no-args 생성자를 간단히 살펴보겠습니다.

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에서 생성자 오버로드가 발생합니다. 자바 프로그램에서 생성자 오버로딩의 예를 살펴보자.

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의 개인 생성자

싱글톤 디자인 패턴은 사용할 수 없습니다. 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 키워드를 사용해야 합니다. 때로는 클래스 변수의 일부 기본값을 설정하는 데 사용됩니다. 다른 생성자 호출은 코드 블록의 첫 번째 명령문이어야 합니다. 또한 무한 루프를 생성하는 재귀 호출이 없어야 합니다. 자바 프로그램에서 생성자 체이닝의 예를 보자.

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

}

Employee 개체에 대한 몇 가지 유용한 정보를 인쇄하기 위해 toString() 메서드를 재정의했습니다. 아래는 위의 프로그램에 의해 생성된 출력입니다.

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

하나의 생성자가 다른 생성자에서 어떻게 호출되는지 확인하십시오. 이를 생성자 연결 프로세스라고 합니다.

자바 슈퍼 생성자

때때로 클래스는 수퍼클래스에서 상속됩니다. 이 경우 수퍼클래스 생성자를 호출해야 하는 경우 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

따라서 Person 클래스의 no-args 또는 기본 생성자가 호출되는 첫 번째 문에 슈퍼 호출이 없었기 때문에 호출은 Student 클래스의 no-args 생성자로 이동했습니다. 따라서 출력. Student 클래스의 매개 변수화된 생성자를 Student st = new Student(34, \Pankaj\);로 사용하는 경우 출력은 다음과 같습니다.

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

여기에서 명시적으로 수퍼클래스 생성자를 호출하기 때문에 출력이 명확하므로 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]

복사 생성자를 사용하는 경우 원본 개체와 해당 복사본은 서로 관련이 없으며 둘 중 하나의 수정 사항이 다른 개체에 반영되지 않습니다. 이것이 자바의 생성자에 대한 전부입니다.