Java

생성자

M9M9 2020. 9. 15. 00:14

객체지향 프로그래밍 중 생성자에 대해 정리해보겠다.

 

 

생성자란

인스턴스(객체) 변수들을 초기화하기 위해 사용하는 메서드이다.

생성자는 인스턴스(객체)를 생성할 때 호출된다.

 

 

생성자의 형태

public class Constructor1 {
	private String name;
	private int age;
	private int height;
	
	Constructor1(){
		name="한";
		age=27;
		height=180;
	}

	public static void main(String[] args) {
		Constructor1 c = new Constructor1();
		System.out.println(c.name); //"한"
        System.out.println(c.age);//27
        System.out.println(c.name); //180
	}
}

생성자는 new 키워드를 통해 인스턴스를 생성할 때 호출된다.

(cf) new키워드가 인스턴스(객체)를 생성하는 것이지 생성자가 객체를 생성하는 것이 아니다.)

 

위의 코드에서는 new Constructor1()을 할때 생성자가 호출된다.

 

 

 

생성자의 조건

생성자에는 꼭 지켜야할 조건들이 있다.

 

1. 클래스명과 이름이 동일해야 한다.

2.  return 타입이 없다.(void가 아니라 리턴 타입 자체가 없다.)

 

이 두 가지는 꼭 지켜야 한다.

 

디폴트 생성자

만약 클래스에 생성자가 한 개도 정의되어있지 않다면 컴파일러는 자동적으로 기본 생성자를 추가하여 컴파일한다.

public class Constructor1 {
	private String name;
	private int age;
	private int height;
	
    // Constructor1(){ } 
    
	public static void main(String[] args) {
		Constructor1 c = new Constructor1();
		System.out.println(c.name); //"null"
        System.out.println(c.age);//0
        System.out.println(c.height); //0
	}
}

위으 코드에서는 생성자가 정의되어있지 않다. 그래서 자동으로 디폴트 생성자가 생성되어 호출된 것이다.

디폴트 생성자는 매개변수도 없고 내부의 내용도 아무것도 없다. 

그러므로 c.name, c.age, c.height의 값이 기본 값으로 들어가 있다.

cf) 클래스의 접근제어자가 public인 경우, 기본 생성자로 public '클래스 이름'(){} 이 추가된다.

 

 

 

단, 생성자가 클래스에 단 한 개라도 정의되어있으면 디폴트 생성자는 생성되지 않는다.

public class Constructor1 {
	private String name;
	private int age;
	private int height;
	
    Constructor1(String name, int age, int height){

		this.name=name;
        this.age=age;
        this.height=height;
    }
    
	public static void main(String[] args) {
		Constructor1 c = new Constructor1("test",10,150);
		System.out.println(c.name);
	
	}
}

이런 식으로 생성자가 생성되어있으면 기본 생성자는 절대 생성되지 않으며,

생성자의 매개변수에 맞게 인자 값을 전달해야 한다.

 

 

생성자 오버 로딩

생성자도 결국 메서드이기 때문에 오버 로딩이 가능하다.

 

public class Constructor1 {
	private String name;
	private int age;
	private int height;
	
    Constructor1(String name, int age, int height){

		this.name=name;
        this.age=age;
        this.height=height;
    }
    Constructor1(String name, int age){

		this.name=name;
        this.age=age;
        this.height=190;
    }
    
	public static void main(String[] args) {
		Constructor1 c = new Constructor1("test",10,150);
		Constructor1 b = new Constructor1("min",60);
		System.out.println(c.name); //test
		System.out.println(b.name); //min
		System.out.println(b.height); //190
	
	}
}

위의 코드와 같이 생성자 오버로딩이 가능하다.

 

 

생성자에서 다른 생성자 호출

메서드 내에서 다른 메서드를 호출할 수 있는 것처럼 생성자도 생성자 내부에서 다른 생성자를 호출할 수 있다.

단, 2가지의 조건은 만족시켜야만 호출할 수 있다.

 

1. 생성자를 호출할 때 생성자명(클래스명) 대신 this 사용해야 한다.

2. 한 생성자 내에서 다른 생성자를 호출할 때 반드시 첫 줄에서만 호출해야 한다.

 

public class Constructor2 {
	private int gear;
	private int speed;
	private String model;
	
	Constructor2(){
		this(3);
		gear=1;
		//Constructor2(3); //에러 !! 생성자 명이 아닌 this를 사용해야하고,
        //생성자의 맨 첫줄에서 다른 생성자를 호출해야한다.
		
	}
	Constructor2(int gear){
		this.gear=gear;
		speed=80;
		model="e-class";
	}

}

참고로 this는 참조 변수로써 인스턴스 자신을 가리킨다.(this에 인스턴스의 주소가 저장되어 있다.)

 

그래서 this.gear이면 인스턴스 변수인 gear를 가리키는 것이고, 그냥 gear는 매개변수의 gear를 가리키는 것이다.

생성자도 똑같이  this를 사용하면 자신의 클래스 내에 있는 생성자를 가리키는 것이다.

 

(단, static 메서드(클래스 메서드)에서는 인스턴스 멤버들을 사용할 수 없는 것처럼 this 역시 사용할 수없다. 그 이유는 static 메서드가 호출된 시점에 인스턴스가 존재하지 않을 수 있기 때문이다)

 

 

 

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

현재 사용 중인 인스턴스를 한 개 더 만들고자 할 때 생성자를 사용할 수 있다.

Constructor2(Constructor2 c){
		gear=c.gear;
		speed=c.speed;
		model=c.model;
}

이런 식으로 만들면 되는데, 이렇게 함으로써 매개변수의 c의 멤버 변수 값들을 구체적으로 몰라도 값을 대입할 수 있다.

 

 

 

또한, 객체이기 때문에 주소를 공유한다고 생각할 수 있는데 그렇지 않다.

public class Constructor2 {
	private int gear;
	private int speed;
	private String model;
	

	Constructor2(int gear){
		this.gear=gear;
		speed=80;
		model="e-class";
	}
	Constructor2(Constructor2 c){
		gear=c.gear;
		speed=c.speed;
		model=c.model;
	}
	

	public static void main(String[] args) {
		Constructor2 c = new Constructor2(2);
		Constructor2 b = new Constructor2(c);
		b.gear=5;
		System.out.println(b.gear);//5
		System.out.println(c.gear);//2

	}
}

 

서로 독립적으로 메모리 공간에 존재하는 별도의 인스턴스이므로 값을 변경해도 b.gear의 값을 변경해도 c의 gear값은 변경되지 않는다.