회원가입

생성자

Beany 2024-09-10

생성자가 필요한 이유


객체를 생성하는 시점에 어떤 작업을 하고 싶다면 생성자(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 같은 변수에 초기값을 설정한다.
아마도 회원 객체를 제대로 사용하기 위해서는 객체를 생성하자 마자 이런 초기값을 설정해야 할 것이다.
이 코드에서 회원 초기값을 설정하는 부분이 계속 반복된다.
메서드를 사용해서 반복을 제거해보자.

 

Main 에서 함수로 초기화


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 가 자기 자신의 데이터를 변경하는 기능(메서드)을 제공하는 것이 좋습니다.

 

 

MemberInit Method로 this 이용 초기화


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);
  • 제약 - 생성자 호출 필수
    • 방금 코드에서 생성자 등장 전 코드를 보자. 이 경우 initMember(...) 를 실수로 호출하지 않으면 어떻게 될까? 이 메서드를 실수로 호출하지 않아도 프로그램은 작동한다. 하지만 회원의 이름과 나이, 성적 데이터가 없는 상태로 프로그램이 동작하게 된다. 만약에 이 값들을 필수로 반드시 입력해야 한다면, 시스템에 큰 문제가 발생할 수 있다. 결국 아무 정보가 없는 유령 회원이 시스템 내부에 등장하게 된다.

생성자의 진짜 장점은 생성할 때, 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다는 점이다. 참고로 생성자를 메서드 오버로딩 처럼 여러개 정의할 수 있는데, 이 경우에는 하나만 호출하면 된다.

 

기본 생성자


기본 생성자

  • 매개변수가 없는 생성자를 기본 생성자라 한다.
  • 클래스에 생성자가 하나도 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동으로 만들어준다.
  • 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않는다.

 

예제를 통해 기본 생성자를 확인해보자

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(){
    }
}

 

생성자 - 오버로딩과 this()


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 는 인스턴스 자신의 참조값을 가리킨다. 그래서 자신의 생성자를 호출한다고 생각하면 된다.

 

 

this() 규칙

  • this()는 생성자 코드의 첫줄에만 작성할 수 있다.

0 0
JAVA
이 공간은 개인 공부를 통해 얻은 정보를 체계적으로 정리하고 공유하는 곳입니다. 학습한 내용, 발견한 지식, 그리고 문제 해결 방법 등을 기록하여 나만의 학습 자료를 구축하고, 필요할 때 쉽게 참고할 수 있는 유용한 자원으로 활용할 수 있도록 합니다.
Yesterday: 456
Today: 217