인프런/김영한 자바

[김영한의 실전 자바 기본편] - 4. 생성자

sson-coding 2025. 9. 9. 14:22

본 글은 김영한 님의 『김영한의 실전 자바 - 기본편』 강의를 학습하며 정리한 내용입니다.
강의 자료에 포함된 일부 코드와 이미지를 참고하여 발췌·활용하였습니다.

자바 기본기를 제대로 다지고 싶으시다면, 아래 링크에서 강의를 확인해 보세요

『김영한의 실전 자바 - 기본편』 보러 가기

본 게시물은 파트너스 활동의 일환으로 작성되었으며, 구매 시 소정의 수수료를 받을 수 있습니다.


생성자

객체를 생성하는 시점에 어떤 작업을 하고 싶다면 생성자를 이용하면 된다. 생성자를 알아보기 전에 생성자가 왜 필요한지 코드로 간단히 알아보자.

MemberInit

public class MemberInit {
 String name;
 int age;
 int grade;
}

MethodInitMain

public class MethodInitMain {
 public static void main(String[] args) {
     MemberInit member1 = new MemberInit();
     member1.name = "user1";
     member1.age = 15;
     member1.grade = 90; MemberInit member2 = new MemberInit();

     member2.name = "user2";
     member2.age = 16;
     member2.grade = 80;

     MemberInit[] members = {member1, member2};

     for (MemberInit s : members) {
         System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
        }
 }
}
이름:user1 나이:15 성적:90
이름:user2 나이:16 성적:80

위 코드처럼 회원 객체를 생성하고 나면 name,age,grade 같은 변수에 초기값을 설정한다. 회원 객체를 제대로 사용하기 위해서는 객체를 생성하자 마자 이런 초기값을 설정해야 할 것이다.

이 코드에는 회원의 초기값을 설정하는 부분이 계속 반복된다. 메서드를 사용해서 반복을 제거해보자.

public class MethodInitMain {
 public static void main(String[] args) {
     MemberInit member1 = new MemberInit();
     initMember(member1, "user1", 15, 90);
     MemberInit member2 = new MemberInit();
     initMember(member2, "user2", 16, 80);
     MemberInit[] members = {member1, member2};
     for (MemberInit s : members) {
     System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
     } 
 }
 static void initMember(MemberInit member, String name, int age, int grade) {
     member.name = name;
     member.age = age;
     member.grade = grade;
 }
}

initMember 메서드를 통해 반복을 제거했다. 앞서 객체 지향에 대해 학습했는데, 이런 경우 속성과 기능을 한 곳에 두는 것이 더 나은 방법이다.

MemberInit - initMember() 추가

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;
     }
}

MethodInitMain 수정

 public class MethodInitMain3 {
     public static void main(String[] args) {
         MemberInit member1 = new MemberInit();
         member1.initMember("user1", 15, 90);
         MemberInit member2 = new MemberInit();
         member2.initMember("user2", 16, 80);
         MemberInit[] members = {member1, member2};
         for (MemberInit s : members) {
             System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
         }
     }
}

수정된 코드에서는 메서드를 호출하면 객체의 멤버 변수에 인자로 넘어온 값을 채운다.


생성자 도입

앞서 initMember 와 같은 메서드를 매번 만들어야 할 수는 없다. 그래서 대부분의 객체 지향 언어는 객체를 생성하자마자 즉시 필요한 기능을 좀 더 편리하게 수행할 수 있도록 생성자 라는 기능을 제공한다.

생성자를 사용하면 객체를 생성하는 시점에 즉시 필요한 기능을 수행할 수 있다.

어떻게 사용하는지 코드로 알아보자.

MemberConstruct

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() 가 바로 생성자이다.

이제 Main 에서 어떻게 사용하는지 알아보자.

ConstructMain

public class ConstructMain1 {
 public static void main(String[] args) {
     MemberConstruct member1 = new MemberConstruct("user1", 15, 90);
     MemberConstruct member2 = new MemberConstruct("user2", 16, 80);
     MemberConstruct[] members = {member1, member2}; for (MemberConstruct s : members) {
     System.out.println("이름:" + s.name + " 나이:" + s.age + " 성적:" + s.grade);
     }
 }
}

생성자 특징

생성자는 다음과 같은 특징을 가진다.

  1. 생성자의 이름은 클래스 이름과 같아야한다.(첫 글자 대문자)
  2. 생성자는 반환 타입이 없다.
  3. 나머지는 메서드와 같다.

생성자 호출

생성자는 인스턴스를 생성하고 나서 즉시 호출된다. 생성자를 호출하는 방법은 new 명령어 다음에 생성자 이름과 매개변수에 맞추어 인수를 전달하면 된다.

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

이렇게 하면 인스턴스를 생성하고 즉시 해당 생성자를 호출한다.

new 키워드를 사용해서 객체를 생성할 때 마지막에 괄호도 포함해야 하는 이유가 바로 생성자 때문이다. 객체를 생성하면서 동시에 생성자를 호출한다는 의미를 포함한다.

생성자 장점

생성자 장점으로는 무엇이 있을까?

중복 호출 제거

생성자 덕분에 객체를 생성하면서 동시에 생성 직후에 필요한 작업을 한번에 처리할 수 있게 되었다.

직접 정의한 생성자를 반드시 호출

객체를 생성할 때 직접 정의한 생성자가 있다면 직접 정의한 생성자를 반드시 호출해야 한다.


기본 생성자

public class MethodInitMain {
 public static void main(String[] args) {
     MemberInit member1 = new MemberInit();
     ...
 }
}

위 코드에서 new MemberInit() 은 매개변수가 없는데 생성자가 호출된다. 이렇게 호출되는 생성자를 기본 생성자라고 한다.

특징

  • 매개변수가 없는 생성자
  • 클래스에 생성자가 하나도 없으면 자바 컴파일러는 매개변수가 없고, 작동하는 코드가 없는 기본 생성자를 자동으로 만들어준다.
  • 생성자가 하나라도 있으면 자바는 기본 생성자를 만들지 않는다.
  • 직접 정의해도 된다.
  • 기본 생성자를 만들어주는 이유 : 기본 생성자를 만들어주지 않는다면 생성자 기능이 필요하지 않은 경우에도 모든 클래스에 개발자가 직접 기본 생성자를 정의해야 하기 때문이다.

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

생성자도 메서드 오보로딩처럼 매개변수만 다르게 해서 여러 생성자를 제공할 수 있다.

public MemberConstruct(String name, int age) { 
    this.name = name;
    this.age = age;
    this.grade = 50;
}
public MemberConstruct(String name, int age, int grade) {
  this.name = name;
  this.age = age;
  this.grade = grade;
}

두 생성자를 비교해 보면 코드가 중복 되는 부분이 있다.

이 때 this() 라는 기능을 사용하면 생성자 내부에서 자신의 생성자를 호출할 수 있다. 여기서 this 는 인스턴스 자신의 참조값을 가리킨다. 즉, 자신의 생성자를 호출한다고 생각하면 된다.

MemberConstruct(String name, int age) {
     this(name, age, 50); //변경
 }
 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; 
}

this()

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


this

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;
 }
}

위 코드처럼 멤버 변수와 메서드의 매개변수의 이름이 같으면 둘을 어떻게 구분해야 할까? 이 경우 멤버 변수보다 매개변수가 코드 블럭의 더 안쪽에 있기 때문에 매개변수가 우선순위를 가진다. 멤버 변수에 접근하려며 앞에 this. 이라고 해주면된다. this 는 인스턴스 자신의 참조값을 가리킨다.

즉, 매개변수의 이름과 멤버 변수의 이름이 같은 경우 this 를 사용해서 둘을 명확하게 구분해야 한다.