객체를 생성하는 시점에 어떤 작업을 하고 싶다면 생성자(Construct)를 이용한다.
생성자를 알아보기 전에 먼저 생성자가 왜 필요한지 코드로 간단히 알아보자.
package construct;
public class MemberInit {
String name;
int age;
int grade;
}
package construct;
public class MemberInitMain1 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
member1.name = "User1";
member1.age = 20;
member1.grade = 90;
MemberInit member2 = new MemberInit();
member2.name = "User2";
member2.age = 16;
member2.grade = 80;
MemberInit[] members = {member1, member2};
for (MemberInit member : members) {
System.out.println("이름: " + member.name + " 나이: " + member.age + " 성적: " + member.grade);
}
}
}
이름: User1 나이: 20 성적: 90
이름: User2 나이: 16 성적: 80
회원 객체를 생성하고 나면 name, age, grade 같은 변수에 초기값을 설정한다.
아마도 회원 객체를 제대로 사용하기 위해서는 객체를 생성하자 마자 이런 초기값을 설정해야 할 것이다.
이 코드에서 회원 초기값을 설정하는 부분이 계속 반복된다.
메서드를 사용해서 반복을 제거해보자.
package construct;
public class MemberInitMain2 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
initMember(member1, "User1", 20, 90);
MemberInit member2 = new MemberInit();
initMember(member2, "User2", 16, 80);
MemberInit[] members = {member1, member2};
for (MemberInit member : members) {
System.out.println("이름: " + member.name + " 나이: " + member.age + " 성적: " + member.grade);
}
}
static void initMember(MemberInit member, String name, int age, int grade) {
member.name = name;
member.age = age;
member.grade = grade;
}
}
이름: User1 나이: 20 성적: 90
이름: User2 나이: 16 성적: 80
initMember(...) 메서드를 사용해서 반복을 제거했습니다. 그런데 이 메서드는 대부분 Member 객체의 맴버 변수를 사용합니다. 우리는 앞서 객체 지향에 대해서 학습했습니다. 이런 경우 속성과 기능을 한 곳에 두는 것이 더 나은 방법입니다. 쉽게 이야기해서 Member 가 자기 자신의 데이터를 변경하는 기능(메서드)을 제공하는 것이 좋습니다.
package construct;
public class MemberInit {
String name;
int age;
int grade;
void initMember(String name, int age, int grade){
this.name = name;
this.age = age;
this.grade = grade;
}
}
package construct;
public class MemberInitMain3 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
member1.initMember("User1", 20, 90);
MemberInit member2 = new MemberInit();
member2.initMember("User2", 16, 80);
MemberInit[] members = {member1, member2};
for (MemberInit member : members) {
System.out.println("이름: " + member.name + " 나이: " + member.age + " 성적: " + member.grade);
}
}
}
이름: User1 나이: 20 성적: 90
이름: User2 나이: 16 성적: 80
프로그래밍을 하다보면 객체를 생성하고 이후에 바로 초기값을 할당해야 하는 경우가 많다.
따라서 앞서 initMember(...) 와 같은 메서드를 매번 만들어야 한다.
그래서 대부분의 객체 지향 언어는 객체를 생성하자마자 즉시 필요한 기능을 좀 더 편리하게 수행할 수 있도록 생성자라는 기능을 제공한다.
생성자를 사용하면 객체를 생성하는 시점에 즉시 필요한 기능을 수행할 수 있다.
생성자는 앞서 살펴본 initMember(...) 와 같이 메서드와 유사하지만 몇가지 다른 특징이 있다.
기존 코드를 유지하기 위해 MemberConstruct 라는 새로운 클래스를 작성하겠다.
package construct;
public class MemberConstruct {
String name;
int age;
int grade;
MemberConstruct(String name, int age, int grade){
this.name = name;
this.age = age;
this.grade = grade;
}
}
생성 시, 클래스 안에 동일한 클래스 명을 넣는다.
package construct;
public class MemberInitMain4 {
public static void main(String[] args) {
MemberInit member1 = new MemberInit();
member1.initMember("User1", 20, 90);
MemberConstruct memberConstruct1 = new MemberConstruct("User1", 20, 90);
MemberInit member2 = new MemberInit();
member2.initMember("User2", 16, 80);
MemberConstruct memberConstruct2 = new MemberConstruct("User2", 16, 80);
MemberInit[] members = {member1, member2};
MemberConstruct[] memberConstructs = {memberConstruct1, memberConstruct2};
for (MemberInit member : members) {
System.out.println("이름: " + member.name + " 나이: " + member.age + " 성적: " + member.grade);
}
for (MemberConstruct memberConstruct : memberConstructs) {
System.out.println("이름: " + memberConstruct.name + " 나이: " + memberConstruct.age + " 성적: " + memberConstruct.grade);
}
}
}
이름: User1 나이: 20 성적: 90
이름: User2 나이: 16 성적: 80
이름: User1 나이: 20 성적: 90
이름: User2 나이: 16 성적: 80
// 생성자 등장 전
MemberInit member1 = new MemberInit();
member1.initMember("User1", 20, 90);
// 생성자 등장 후
MemberConstruct memberConstruct1 = new MemberConstruct("User1", 20, 90);
생성자의 진짜 장점은 생성할 때, 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다는 점이다. 참고로 생성자를 메서드 오버로딩 처럼 여러개 정의할 수 있는데, 이 경우에는 하나만 호출하면 된다.
기본 생성자
예제를 통해 기본 생성자를 확인해보자
package construct;
public class MemberDefault {
String name;
int age;
}
package construct;
public class MemberDefaultMain {
public static void main(String[] args) {
MemberDefault memberDefault = new MemberDefault();
System.out.println("memberDefault.name = " + memberDefault.name);
System.out.println("memberDefault.age = " + memberDefault.age);
}
}
이렇게 만들면 자동으로 아래와 같이 만들어주는 것이다.
package construct;
public class MemberDefault {
String name;
public MemberDefault(){
}
}
package construct;
public class MemberConstruct {
String name;
int age;
int grade;
MemberConstruct(String name, int age) {
this(name, age, 50); // this()를 이용해 다른 생성자 호출
}
MemberConstruct(String name, int age, int grade){
this.name = name;
this.age = age;
this.grade = grade;
}
}
위와 같은 방식으로 this 를 이용해서 사용할 수 있다.
이때 this() 라는 기능을 사용하면 생성자 내부에서 자신의 생성자를 호출할 수 있습니다. 참고로 this 는 인스턴스 자신의 참조값을 가리킨다. 그래서 자신의 생성자를 호출한다고 생각하면 된다.