Java 생성자 - 도입

앞의 코드를 살펴보도록 한다. Student 클래스에서 initStudent 메소드가 있으며 Main 에서 매번 init 으로 학생으로 초기화를 해주어야 했다.

이러한 객체를 생성하고 초기화하는 작업이 반복되는 코드를 개선하기 위해 생성자(Construct) 를 사용해보도록 한다. 생성자는 객체를 생성하자마자 바로 필요한 메소드를 수행이 가능하도록 한다.

Student.java

public class Student {
    String name;
    int age;
    int grade;

    void initStudent(String name, int age, int grade) {
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student();
        student1.initStudent( "guest1", 14, 90);
        Student student2 = new Student();
        student2.initStudent( "guest2", 19, 70);

        Student[] students = {student1, student2};

        for (Student s : students) {
            System.out.println("학생이름: " + s.name + ", 학생 나이: " + s.age + ", 학생 점수: " + s.grade);
        }
    }
}

Main 코드에서 객체를 생성하자마자 initStudent 메소드로 초기화하는 작업을 볼 수 있다.

객체를 생성하는 즉시 초기화 없이 필요한 기능을 수행하도록 생성자를 익혀보자.


생성자 생성 방법

생성자를 사용하는 방법은 클래스명과 똑같은 메소드를 만들어주면 된다.

MemberConstruct.java

public class MemberConstruct {
    String name;
    int age;
    int grade;

    MemberConstruct(String name, int age, int grade) {
        System.out.println("생성자 호출 name = " + name + ", age=" + age + ", grade=" + grade);
        this.name = name;
        this.age = age;
        this.grade = grade;
    }
}

이 코드에서 다음 부분이 생성자다.

MemberConstruct(String name, int age, int grade) {
    System.out.println("생성자 호출 name = " + name + ", age=" + age + ", grade=" + grade);
    this.name = name;
    this.age = age;
    this.grade = grade;
}

생성자는 메소드와 비슷하지만 차이가 있다.

  • 생성자의 이름은 클래스 이름과 동일해야함. 따라서 첫 글자로 대문자로 시작
  • 생성자는 반환 타입이 없다. 비워두기
  • 그 외 메소드와 동일하다.

다음으로 Main 클래스를 살펴본다.

Main.java

public class Main {
    public static void main(String[] args) {
        MemberConstruct m1 = new MemberConstruct("guest1", 14, 90);
        MemberConstruct m2 = new MemberConstruct("guest2", 19, 80);

        MemberConstruct[] members = {m1, m2};

        for (MemberConstruct member : members) {
            System.out.println("이름: " + member.name + ", 나이: " + member.age + ", 점수: " + member.grade);
        }
    }
}

실행결과

생성자 호출 name = guest1, age=14, grade=90
생성자 호출 name = guest2, age=19, grade=80
이름: guest1, 나이: 14, 점수: 90
이름: guest2, 나이: 19, 점수: 80

생성자 호출

생성자를 호출 하는 방법은 new 명령어 다음에 생성자 이름과 매개변수를 맞춰 인수를 전달한다.

new 생성자/클래스이름( 생성자/클래스와 맞는 인수목록 )

Main클래스에서 MemberConstruct m1 = new MemberConstruct("guest1", 14, 90); 인수 값으로 넘겨 주고 있다. 이는 MemberConstruct 클래스에서 생성자를 만들 때 파라미터와 맞추기 위함이다. Java는 이 객체를 생성하고 메모리에 만들어지자마자 MemberConstruct(String name, int age, int grade) 인스턴스 생성자를 호출한다.

즉, 정리하면 다음과 같은 순서다

  • 객체를 생성과 동시에 클래스의 생성자 확인
  • 생성하면서 new MemberConstruct("guest1", 14, 90) 인수 값의 조건 확인
  • MemberConstruct 생성자를 메모리로 불려와 코드 블록을 실행함
참고로 new 명령어를 실행할 때 (); 괄호를 넣게 되는데, 그 이유가 생성자 때문이다. 아무 역할이 없는 빈 생성자로 객체를 생성하면 생성자를 동시에 호출한다는 의미이다.

생성자 장점

생성자 장점으로 중복 호출을 줄일 수 있고, 조건을 강제할 수 있다.

중복 호출 제거

생성자가 없을 때의 코드는 다음과 같이 어떤 작업을 수행하기 위해서는 메소드를 한번 더 호출한다.

생성자가 없는 경우 - 중복 호출

MemberInit member = new MemberInit();
member.initMember("guest", 14, 90);

생성자 사용 - 중복 호출 제거

MemberConstruct member = new MemberConstruct("guest1", 14, 90);

제약사항 - 생성자 호출 조건 필수

생성자가 없는 경우 코드로 iniMember(...) 메소드를 호출하지 않아도 동작하나, 생성된 member 인스턴스에는 아무런 값이 없는 상태가 된다. 뒤늦게 해당 인스턴스를 사용한 경우 자바는 크래쉬가 발생되어 시스템에 큰 문제가 발생한다.

생성자는 객체를 생성할 때 직접 정의한 생성자를 반드시 호출한다.
앞서 만든 코드에서 다음과 같이 생성자를 호출하면 오류가 발생할 것이다.

MemberConstruct member = new MemberConstruct();

자바를 빌드하면 컴파일이 조건이 필요하다고 알려주므로 인수 값을 채워 해결할 수 있다. 즉, 필수 값을 보장한다.

참고: 생성자는 오버로딩이 가능하다.
다만, 객체 생성시 오버로딩한 생성자 하나만 호출한다.