이번에는 this() 메서드를 알아보자. this 키워드와 매우 비슷하게 생겼지만 의미는 전혀 다르다. this() 메서드는 자신이 속한 클래스 내부에 다른 생성자를 호출하는 명령이다. 만일 클래스 명이 A라면 A() 생성자를 호출하는 것이라고 생각하면 된다. 만일 this(3)이라면 A(3), 즉 int 데이터 하나를 입력받는 생성자를 호출하라는 말이 된다.
this()메서드를 구성할 때는 반드시 2가지 문법적 규칙을 지켜야 한다. 첫 번째는 생성자의 내부에서만 사용할 수 있다. 즉, 생성자의 내부에서만 또 다른 생성자를 호출할 수 있다는 말이다. 두 번째는 생성자의 첫 줄에 위치해야 한다. 이 둘 중 어느 하나라도 지켜지지 않으면 바로 오류가 발생한다.
다음 예제를 살펴보자. 클래스 A에는 2개의 생성자가 있다. 생성자가 2개이므로 객체를 생성하는 방법도 2개다. 첫 번째 생성자는 기본 생성자로 내부에는 1개의 출력문이 있다. 따라서 A a1 = new A()와 같이 객체를 생성하면 이 과정에서 첫 번째 생성자가 호출되고 그 결과 "첫 번째 생성자"라는 문자열이 출력된다. 두 번째 생성자로 객체를 생성하는 A a2 = new A(3)을 실행하면 일단 객체 생성 과정에서 두 번째 생성자가 실행된다. 이 생성자의 첫 번째 명령은 this()이고 이는 자신의 또 다른 생성자인 A()를 호출하라는 말이다. 따라서 먼저 첫 번째 생성자가 호출된 후 나머지 코드가 실행되므로 "첫 번째 생성자"와 "두 번째 생성자"가 모두 출력되는 것이다.
class A {
A() {
System.out.println("첫 번째 생성자");
}
A(int a){
this(); // 반드시 생성자의 첫 줄에 위치해야 함.
System.out.println("두 번째 생성자");
}
}
/*
void abc(){
this(); 메서드에선 this() 메서드 사용 불가능
*/
public class jh {
public static void main(String[] args) {
// 객체 생성
A a1 = new A(); // 첫 번째 생성자 호출
System.out.println();
A a2 = new A(3); // 두 번째 생성자 호출 (생성자의 내부에서 첫 번째 생성자 호출)
}
}
결과
이런 문법 요소가 생긴 이유는 무엇일까? 앞에서 말한 것처럼 객체를 생성하는 것과 더불어 생성자의 주요 역할은 필드를 초기화하는 것이라고 했다. 다음 예제를 살펴보자.
class A{
int m1, m2, m3, m4;
A(){
m1 = 1;
m2 = 2;
m3 = 3;
m4 = 4;
}
A(int a){
m1 = a; // 두 번째 생성자가 첫 번째 생성자와 다른 점
m2 = 2;
m3 = 3;
m4 = 4;
}
A(int a, int b){
m1 = a;
m2 = b; // 세 번째 생성자가 두 번째 생성자와 다른 점
m3 = 3;
m4 = 4;
}
}
클래스 A에는 4개의 필드와 3개의 생성자가 있다. 각 생성자에는 필드를 초기화하는데 초기화 하는 방식이 약간 차이가 있다. 첫 번째 생성자는 4개의 필드를 각각 초기화 했으며, 두 번째 필드는 첫 번째 필드에만 입력받은 값을 대입하고 나머지는 첫 번째 생성자와 동일하게 초기화한다. 마지막 생서자 또한 두번째 생성자와 비교해 2개의 필드를 전달받은 값으로 초기화한다는 점만 다르다. 이미 눈치챘겠지만 각 생성자마다 중복되는 코드를 많이 포함하고 있다 . 4개의 필드만을 고려했지만, 만일 20개의 필드라면 각 생성자는 모두 20줄의 초기화 코드를 포함하고 있을 것이다. 만일 두 번째 생성자에서 첫 번째 생성자를 호출할 수 있다면 두 번째 생성자에서는 1개의 필드만 추가로 초기화하면 된다. 이와 마찬가지로 세 번째 생성자에서 두 번째 생성자를 호출할 수 있다면 추가로 1개의 필드만 초기화하면 된다. 이것이 바로 this() 메서드가 필요한 이유다. 즉, 다음과 같이 this() 메서드를 이용해 생성자의 중복을 제거할 수 있다,
int m1, m2, m3, m4;
A(){
m1 = 1;
m2 = 2;
m3 = 3;
m4 = 4;
}
A(int a){
this();
m1 = a;
}
A(int a, int b){
this(a);
m2 = b;
}
}
class A {
int m1, m2, m3, m4;
A() {
m1 = 1;
m2 = 2;
m3 = 3;
m4 = 4;
}
A(int a) {
this();
m1 = a;
}
A(int a, int b) {
this(a);
m2 = b;
}
void print() {
System.out.print(m1 + " ");
System.out.print(m2 + " ");
System.out.print(m3 + " ");
System.out.print(m4);
System.out.println();
// 클래스 A의 모든 필드값을 출력
}
}
class B {
int m1, m2, m3, m4;
B() {
m1 = 1;
m2 = 2;
m3 = 3;
m4 = 4;
}
B(int a){
this(); // B() 생성자 호출
m1 = a;
}
B(int a, int b) { // B(int a) 생성자 호출
this(a);
m2 = b;
}
/*
B(int a, int b){
this();
m1 = a; B() 생성자를 호출하고 두 필드 값을 한 번에 수정할 수도 있음
m2 = b;
*/
void print() {
System.out.print(m1 + " ");
System.out.print(m2 + " ");
System.out.print(m3 + " ");
System.out.print(m4);
System.out.println();
}
}
public class jh {
public static void main(String[] args) {
// 3가지 객체 생성(this() 미사용)
A a1 = new A();
A a2 = new A(10);
A a3 = new A(10,20);
a1.print();
a2.print();
a3.print();
System.out.println();
// 3가지 객체 생성(this() 사용)
B b1 = new B();
B b2 = new B(10);
B b3 = new B(10,20);
b1.print();
b2.print();
b3.print();
}
}
결과