시소당
자, 이제 상속의 마지막 이야기를 하기 전에 한 가지 알아야 할 것이 있다.
바로 constructor(생성자)라고 부르는 것이다.
다음의 예제를 보자.
Manager m = new Manager();
뭐하는 코드인가? 바로 class Manager를 근거로 해서 새로운 object를 만들고 있는 문장이다.
그런데, 아마 궁금하게 생각하는 사람도 있었을 것이다. new 다음에 왜 Manager()라고 썼을까? Manager()란 method를 호출하는 문장과 유사하지 않는가?
그렇다. 그렇게 생각했다면 예리한 생각을 한 것이다. 다음의 예제를 보자.
class Manager extends Employee{
String department;
Employee subordinamtes [];
long bonus() {
return salary * 3;
}
Manager() {
System.out.println("난 constructor.");
}
}
이 예제에서 자세히 볼 부분이 바로 line 7이다. Manager()라는 method가 있다.
그런데 생김새가 좀 이상하다.
다 아시는 사실이겠지만 Java에서 사용되는 method는 반드시 return type이 있어야 한다.
return 되는 값이 없으면 void라고 반드시 써야 한다. 그런데 이 method는 아예 그것도 없다.
또 한가지, 어랏! method 이름이 대문자로 시작하네? 원래 member들은 모두 소문자로 시작해야 하는데 말이다(물론 대문자로 시작한다고 해서 compile error발생하는 것은 아니다.
convention일 뿐이다). 더군다나 자신의 class 이름과 정확히 동일하기까지 하다.
그렇다. 지금 설명한 특징을 가지고 있는 것이 바로 constructor이다. 즉, return type이 없고 class 이름과 대소문자까지 정확히 같은 것.
그럼 constructor가 무엇인가? 이것은 일반 method랑 분명히 다르다. 이것은 object가 생성될 때 단 한 번 자동으로 수행된다(또한 무조건 수행된다).
따라서 위의 예제 class를 object로 만들면 어떻게 될까? 다음을 보자.
Manager m = new Manager(); // 이순간 화면에 "난 constructor" 문장이 찍힌다.
위의 new 다음에 나오는 Manager()가 정확히 constructor를 호출하는 것과 같지 않은가.
하여간 constructor가 수행되기 때문에 line 8의 코드가 수행되어 화면에 "난 constructor"라 찍히게 되는 것이다.
그러면 이 같은 constructor를 사용하는 이유가 무엇인가? 일반적으로 constructor는 member 변수를 초기화 등에 주로 쓰인다(즉, object의 초기화에 주로 쓰인다).
그런데 또 궁금한 점이 있을 수 있다. 지금까지 나는 constructor를 만들어 사용한 적이 없는데도 위의 코드처럼 object를 만들지 않았던가? constructor가 무조건 수행된다면, 만들지 않은 constructor를 호출하니 당연히 compile error발생해야 하는 거 아닌가?
그렇다. constructor는 반드시 있어야 한다. 그렇다면 뻔한 이야기이다. 내가 만들지도 않았는데, object가 생성되었다? 이 말은 누군가가 나 대신 constructor를 만들어 주었다는 결론이다. 그럼 누가 만들어 주었는가?
바로 compiler가 constructor가 존재하지 않으면 대신 하나를 만들어 주는데, 내용은 하나도 없는 빈 constructor를 만들어 줄뿐이다(그러나 constructor가 존재한다는 것이 중요한 사실인 것이다).
이렇게 compiler가 자동으로 생성해 준 constructor를 default constructor라고 한다. 이 용어는 꼭 기억해야 한다. default constructor는 다음과 같이 생겼다.
Manager() { // argument도 없고, 하는 일도 없다.}
좀더 구체적인 다음의 예제를 보자.
class Manager extends Employee{
String department;
Employee subordinamtes [];
long bonus() {
return salary * 3;
}
Manager() {
name = "손오공";
salary = 500;
department = "인사부";
}
}
이 class를 object로 만들면, member 변수 값이 초기화된다.
이런 용도로 주로 constructor가 사용된다. 여기서 또 반드시 알아두어야 할 것이 있다.
이렇게 명시적으로 constructor를 만들면 compiler가 default constructor는 만들어 주지 않는다.
좀 더 달라진 예제를 보자.
class Manager extends Employee{
Manager(String name) {
this(name, 100);
}
Manager(String name, Long salary) {
this.name = name;
this.salary = salary;
}
}
위의 예제에 관해서 할 말이 많이 있다. 먼저 2 line, 5 line이 constructor들인데 이렇게 같은 이름의 method를 얼마든지 만들 수 있다. 이것을 보고 method overloading이라고 부른다.
method overriding과 더불어 꼭 기억해야 한다(overriding은 부모로부터 상속받은 것을 재정의 하는 것을 의미한다).
method overloading을 할 때 주의할 사항이 있는 데 다음과 같다.
같은 이름의 method들의 return type은 같아도 되고 달라도 된다. 그러나 반드시 argument는 달라야 한다. 다음이 그 예이다.
int func(int x) { ... }
int func(int x, int y) { ... }
char func(char x, String y) { ... }
위의 3가지 method를 호출할 때 어떤 method가 호출될 것인가? 만약 func(3)이라고 호출하면 첫 번 째 것이, func(3,3)하면 두 번 째 것이, func('a', "안녕")하면 세 번 째 것이 호출된다.
만약 func(3,'3')하면? 이건 error이다. 해당하는 method가 없기 때문이다.
이렇게 method overloading을 이용하면 강력한 program을 개발할 수 있다.
자, 이제 constructor에 대한 이야기를 계속해보자. 위의 예에서 같은 이름의 constructor가 두 개 있다.
즉, method overloading이 일어난 것이다(constructor가 일반 method와는 좀 다르지만 그래도 method의 일종임을 기억하자).
그러면 이 Manager class의 object를 만들려면 어떻게 해야 하는가? 다음과 같다.
Manager m = new Manager("웹아이티");
이렇게 하면 위의 예제의 2 line의 constructor가 수행될 것이다. 그런데 이 constructor의 내용을 보면 재미있다. 3 line의 코드에서 this() method를 호출하는 데, 이는 다른 constructor를 호출하는 것이다. this를 그냥 쓰면 자신의 object를 지칭하는데 사용되고, this()는 자신의 object의 다른 constructor를 호출하는데 사용된다.
3 line에서 this(name, 100); 라고 호출하면 method overloading에 의해서 5 line의 constructor가 호출하게 된다. 이 때 name에는 "웹아이티"라는 String object가 넘어간다.
그럼 다음과 같이 호출하면?
Manager m = new Manager("웹아이티", 500);
5 line의 constructor가 바로 호출된다. 그럼, 다음과 같이 호출하면?
Manager m = new Manager();
이미 말했지만 이 문장은 default constructor를 호출하는 문장이다.
그러나 예제에서는 default constructor가 없다.
아까도 말했지만, constructor를 하나라도 만들면 compiler는 default constructor를 안 만들어 준다는 사실을 잊지 말자. 따라서 위의 문장은 error가 발생하는 것이다.
그러므로 여기서 주의할 사항이 있다.
의도적으로 constructor를 만들 때 반드시 default constructor에 해당하는 constructor를 만들어 주는 것이 좋다. (default constructor는 argument가 없는 것을 말한다.)
다음의 예제를 보자.
class Manager extends Employee{
Manager() { // default constructor
this("자바누리");
}
Manager(String name) {
this(name, 100);
}
Manager(String name, Long salary) {
this.name = name;
this.salary = salary
}
}
위의 예제에서 2 line이 default constructor에 해당된다. 3 line은 무엇을 의미하는지 알 것이다.
꼭 default constructor에 body를 넣을 필요는 없다. 다음과 같이 해도 된다.
Manager() { // default constructor}
한 가지 기억할 점은 constructor는 상속되지 않는다는 것이다. 즉, 상속을 받을 때 부모의 모든 것을 가지고 오지만, constructor는 상속되지 않음을 기억하자.