Java

생성자 Constructor

hs_developer 2022. 3. 19. 13:54

무언가를 새로 생성하는 역할을 하는 것처럼 보이지만 실제로는 인스턴스가 생성될 때 가장 먼저 호출되는 함수다. 

 

// 기본적인 생성자 형태

public class ObjectExample(){

	public ObjectExample(){
    	System.out.println("생성자 호출됨")
    }
 }

 

생성자를 작성하는 2가지 조건

 

  • 생성자 이름은 클래스 이름과 같아야 한다.
  • return 값이 없다.

 

 

생성자 특징

 

  • 생성자도 오버로딩이 가능하기 때문에 하나의 클래스에 여러 개의 생성자가 존재할 수 있다.
  • 연산자 new가 인스턴스를 생성하지, 생성자가 인스턴스를 생성하는 것이 아니기 때문에 혼동하면 안된다.

 

 

1. 기본 생성자 

 

만약 클래스에 생성자가 따로 정의되어 있지 않다면, 컴파일러는 자동적으로 생성자를 추가한다. 컴파일러는 매개변수도 없고, 아무런 내용이 없는 아주 기본적인 생성자를 추가해주는데 이를 기본 생성자라 한다.

 

public class ConstructorTest {
	public static void main(String[] args) {
		Data1 data1 = new Data1();
		Data2 data2 = new Data2();
		
	}
}


class Data1 {
	int value;
	
	// 기본 생성자
	Data1() {}
}

class Data2 {
	int value;
	
	// 기본 생성자
	Data2() {}
}

 

 

2. 매개 변수가 있는 생성자  (이게 오버로딩인 듯)

 

생성자도 메소드처럼 매개 변수 선언 시 값을 넘겨받아 인스턴스 초기화 작업에 사용할 수 있다. 

인스턴스마다 각기 다른 값으로 초기화 되어야 할 경우가 많기 때문에 매개 변수를 이용한 초기화는 유용하다.

 

// 매개 변수를 통한 초기화

public class CarTest {
	public static void main(String[] args) {
		
		Car car1 = new Car();
		System.out.println("car1 :" + car1.color + " / " + car1.gearType + " / " + car1.door);
		
		// 인스턴스 초기화 작업
		car1.color = "black";
		car1.gearType = "auto";
		car1.door = 4;
		
		// 인스턴스 생성, 초기화 작업 동시 수행 (오버로딩)
		Car car2 = new Car("white", "auto", 5);
		
		System.out.println("car1 :" + car1.color + " / " + car1.gearType + " / " + car1.door);
		System.out.println("car2 :" + car2.color + " / " + car2.gearType + " / " + car2.door);
	}
}

class Car {
	String color;
	String gearType;
	int door;
	
	// 기본 생성자
	Car() {}
	
	// 매개변수가 있는 생성자
	Car(String color, String gearType, int door) {
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}
}

 

// 결과 값

car1 :null / null / 0
car1 :black / auto / 4
car2 :white / auto / 5

 

 

위의 예제에는 2개의 생성자가 존재한다.

 

기본 생성자의 경우 인스턴스를 생성한 뒤 인스턴스 변수들의 초기화 작업을 따로 해줘야 하지만, 

 

매개변수가 있는 생성자의 경우 인스턴스를 생성함과 동시에 인스턴스 변수들의 초기화 작업까지 수행함으로서 코드를 보다 간결하고 직관적으로 만들 수 있는 장점이 있다.

 

클래스를 작성할 때 다양한 생성자를 제공함으로서 인스턴스 생성 후 별도로 초기화 작업을 다시 하지 않는 것이 바람직하다.

 

 

 

3. 생성자에서 다른 생성자 호출하기 - this(), this

 

생성자 간에 서로 호출이 가능한데 다음과 같은 조건을 만족한다.

 

  • 생성자 이름으로 클래스 이름 대신 this 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출 가능하다.

 

 

// 생성자 호출의 잘못된 예

Car(String color) {
	// 이 라인에서 다른 생성자를 호출해야 함
    door = 5;
    Car(color, "auto", 4) // this(color, "auto", 4); 로 호출해야 함
}

 

 

생성자에서 다른 생성자를 호출할 때, 첫 번째 라인에 작성해야 하는 이유는

 

생성자 내에서 초기화 작업 도중에 다른 생성자를 호출하면 호출된 다른 생성자 내에서도 멤버 변수를 초기화 할 것이기 때문에

 

이전에 수행한 멤버 변수의 초기화 작업이 무의미해진다.

 

 

public class CarTest2 {
	public static void main(String[] args) {
		Car2 carOne = new Car2();
		Car2 carTwo = new Car2("blue");
		
		System.out.println("carOne: " + carOne.color + "/" + carOne.gearType + "/" + carOne.door);
		System.out.println("carTwo: " + carTwo.color + "/" + carTwo.gearType + "/" + carTwo.door);
	}
}

class Car2 {
	
	String color;
	String gearType;
	int door;
	
	Car2() {
		this("white", "auto", 4); // 생성자 호출 시에는 반드시 생성자의 첫 번째 라인에 작성
	}
	
	Car2(String color) {
		this(color, "auto", 4); // 생성자 호출 시에는 반드시 생성자의 첫 번째 라인에 작성
	}
	
	Car2(String color, String gearType, int door) {
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}
}

 

 

위의 예제에 this와 this()가 등장하는데 차이점은 아래와 같다.

 

  • this : 인스턴스 자신을 가리키는 참조변수, 인스턴스의 주소가 저장되어 있다.
  • this(), this(매개변수) : 생성자, 같은 클래스의 다른 생성자를 호출할 때 사용한다.

 

 

4. 생성자를 이용한 인스턴스의 복사

 

현재 사용하고 있는 인스턴스와 같은 상태를 갖는 인스턴스를 하나 더 만들고자 할 때 생성자를 이용할 수 있다. 

 

두 인스턴스가 같은 상태를 갖는다는 것은 인스턴스 변수가 동일한 값을 가지고 있는 것을 의미한다.

 

하나의 클래스로부터 생성된 인스턴스의 메소드, 클래스 변수는 동일하기 때문에 인스턴스 차이는 인스턴스마다  각기 다른 값을 가질 수 있는 것은 인스턴스 변수 뿐이다.

 

 

Car(Car car2) {
    color = car2.color;
    gearType = car2.gearType;
    door = car2.door;
 }

 

 

위의 코드는 Car 클래스의 참조 변수를 매개 변수로 한 생성자이다.

 

매개 변수로 넘겨진 참조 변수가 가리키는 Car 인스턴스의 인스턴스 변수인 color, gearType, door의 값을 인스턴스 자신으로 복사한다.

 

 

public class CarTest3 {
	public static void main(String[] args) {
		Car3 carOne = new Car3();
		Car3 carTwo = new Car3(carOne);
		
		System.out.println("carOne: " + carOne.color + "/" + carOne.gearType + "/" + carOne.door);
		System.out.println("carOne: " + carTwo.color + "/" + carTwo.gearType + "/" + carTwo.door);
		
		carOne.door = 6;
		System.out.println("carOne.door = 6; 수행 후");
		
		System.out.println("carOne: " + carOne.color + "/" + carOne.gearType + "/" + carOne.door);
		System.out.println("carOne: " + carTwo.color + "/" + carTwo.gearType + "/" + carTwo.door);
	}
}

class Car3 {
	String color;
	String gearType;
	int door;
	
	Car3() {
		this("white", "auto", 4);
	}
	
	Car3(Car3 car3) {
		color = car3.color;
		gearType = car3.gearType;
		door = car3.door;
	}
	
	Car3(String color, String gearType, int door) {
		this.color = color;
		this.gearType = gearType;
		this.door = door;
	}
}

 

// 결과 값

carOne: white/auto/4
carOne: white/auto/4
carOne.door = 6; 수행 후
carOne: white/auto/6
carOne: white/auto/4