[Java ] 개념노트 22 생성자란 무엇인가? 객체를 만들 때 필드 값 초기화하기

[Java 개념노트 22] 생성자란 무엇인가? 객체를 만들 때 필드 값 초기화하기

안녕하세요. Java 개념노트 시리즈 스물두 번째 글입니다.

지난 글에서는 자바 객체지향의 시작점인 클래스와 객체에 대해 정리했습니다. 이번 글에서는 객체를 만들 때 자동으로 실행되는 특별한 메서드인 생성자에 대해 알아보겠습니다.

객체를 만들고 나서 필드에 값을 하나씩 넣는 방식은 가능하지만, 객체가 많아질수록 코드가 길어질 수 있습니다. 생성자를 사용하면 객체를 생성하는 순간 필요한 값을 바로 넣어줄 수 있습니다.


1. 생성자란?

생성자는 객체가 생성될 때 자동으로 호출되는 특별한 메서드입니다.

생성자는 주로 객체의 필드 값을 초기화할 때 사용합니다. 예를 들어 학생 객체를 만들 때 이름, 나이, 점수를 처음부터 넣어주고 싶다면 생성자를 사용할 수 있습니다.

쉽게 말하면
생성자는 객체가 태어날 때 처음 값을 넣어주는 초기 설정 공간입니다.

2. 생성자가 필요한 이유

먼저 생성자를 사용하지 않고 객체를 만드는 코드를 보겠습니다.

public class Main {
    public static void main(String[] args) {
        Student student = new Student();

        student.name = "건";
        student.age = 20;
        student.score = 90;

        student.printInfo();
    }
}

class Student {
    String name;
    int age;
    int score;

    void printInfo() {
        System.out.println("이름: " + name + ", 나이: " + age + ", 점수: " + score);
    }
}

실행 결과는 다음과 같습니다.

이름: 건, 나이: 20, 점수: 90

이 방식도 틀린 것은 아닙니다. 하지만 객체를 만들 때마다 필드 값을 따로 넣어야 하므로 코드가 반복됩니다.

3. 생성자를 사용한 경우

이번에는 생성자를 사용해서 객체를 만들 때 값을 바로 넣어보겠습니다.

public class Main {
    public static void main(String[] args) {
        Student student = new Student("건", 20, 90);

        student.printInfo();
    }
}

class Student {
    String name;
    int age;
    int score;

    Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    void printInfo() {
        System.out.println("이름: " + name + ", 나이: " + age + ", 점수: " + score);
    }
}

실행 결과는 다음과 같습니다.

이름: 건, 나이: 20, 점수: 90

new Student("건", 20, 90)를 실행하는 순간 생성자가 호출되고, 전달한 값들이 필드에 저장됩니다.

4. 생성자의 기본 구조

생성자는 일반 메서드와 비슷해 보이지만 중요한 차이가 있습니다.

클래스이름(매개변수) {
    객체 생성 시 실행할 코드;
}

예를 들어 Student 클래스의 생성자는 다음과 같이 작성합니다.

Student(String name, int age) {
    this.name = name;
    this.age = age;
}
구성 요소 설명
생성자 이름 클래스 이름과 반드시 같아야 합니다.
반환타입 생성자는 반환타입을 작성하지 않습니다.
매개변수 객체 생성 시 전달받을 값을 작성합니다.
중괄호 객체 생성 시 실행할 초기화 코드를 작성합니다.

중요
생성자는 클래스 이름과 같아야 하고, 반환타입을 작성하지 않습니다. void도 작성하지 않습니다.

5. 생성자는 언제 호출될까?

생성자는 new 키워드로 객체를 만들 때 자동으로 호출됩니다.

Student student = new Student("건", 20, 90);

위 코드에서 new Student("건", 20, 90) 부분이 객체를 생성하면서 생성자를 호출하는 부분입니다.

new Student("건", 20, 90)
        ↓
Student 생성자 호출
        ↓
필드 값 초기화
        ↓
객체 생성 완료

6. 기본 생성자란?

기본 생성자는 매개변수가 없는 생성자입니다.

class Student {
    String name;
    int age;

    Student() {
        System.out.println("Student 객체가 생성되었습니다.");
    }
}

기본 생성자는 다음처럼 호출할 수 있습니다.

Student student = new Student();

괄호 안에 전달하는 값이 없기 때문에 매개변수가 없는 생성자가 호출됩니다.

7. 생성자를 작성하지 않으면 어떻게 될까?

클래스에 생성자를 하나도 작성하지 않으면 자바가 자동으로 기본 생성자를 만들어줍니다.

class Student {
    String name;
    int age;
}

위 클래스에는 생성자가 보이지 않습니다. 하지만 자바는 내부적으로 아래와 같은 기본 생성자가 있는 것처럼 처리합니다.

Student() {
}

그래서 다음 코드가 가능합니다.

Student student = new Student();

8. 생성자를 직접 만들면 기본 생성자는 자동 제공되지 않는다

주의할 점이 있습니다. 생성자를 하나라도 직접 작성하면 자바는 기본 생성자를 자동으로 만들어주지 않습니다.

class Student {
    String name;
    int age;

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

위 클래스에는 Student(String name, int age) 생성자만 있습니다. 이 경우 아래 코드는 오류가 발생합니다.

Student student = new Student();

매개변수가 없는 생성자가 없기 때문입니다. 기본 생성자도 필요하다면 직접 작성해야 합니다.

class Student {
    String name;
    int age;

    Student() {
    }

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

핵심 포인트
생성자를 하나라도 직접 만들면 기본 생성자는 자동으로 제공되지 않습니다. 필요하다면 기본 생성자도 직접 작성해야 합니다.

9. 매개변수가 있는 생성자

매개변수가 있는 생성자를 사용하면 객체를 만들 때 필요한 값을 바로 전달할 수 있습니다.

class Student {
    String name;
    int age;
    int score;

    Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
}

객체를 만들 때는 다음처럼 값을 전달합니다.

Student student = new Student("건", 20, 90);

전달된 값은 생성자의 매개변수로 들어가고, 생성자 안에서 필드에 저장됩니다.

10. this 키워드가 필요한 이유

생성자 안에서 this를 사용하는 이유는 필드와 매개변수를 구분하기 위해서입니다.

class Student {
    String name;
    int age;

    Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

여기서 왼쪽의 this.name은 객체의 필드이고, 오른쪽의 name은 생성자로 전달받은 매개변수입니다.

코드 의미
this.name 현재 객체의 name 필드
name 생성자로 전달받은 매개변수

this 키워드는 다음 글에서 더 자세히 정리하겠습니다. 이번 글에서는 현재 객체의 필드를 가리킬 때 사용한다 정도로 이해하면 됩니다.

11. this를 쓰지 않으면 어떻게 될까?

필드 이름과 매개변수 이름이 같을 때 this를 쓰지 않으면 의도한 대로 값이 저장되지 않을 수 있습니다.

class Student {
    String name;
    int age;

    Student(String name, int age) {
        name = name;
        age = age;
    }
}

위 코드는 보기에는 값을 저장하는 것처럼 보이지만, 실제로는 매개변수끼리 대입하는 형태가 됩니다. 객체의 필드에는 값이 제대로 들어가지 않습니다.

그래서 필드와 매개변수 이름이 같다면 다음처럼 this를 사용해야 합니다.

Student(String name, int age) {
    this.name = name;
    this.age = age;
}

12. 생성자 오버로딩

생성자도 메서드처럼 오버로딩할 수 있습니다. 즉, 매개변수의 개수나 자료형을 다르게 해서 여러 개의 생성자를 만들 수 있습니다.

class Student {
    String name;
    int age;
    int score;

    Student() {
        name = "이름 없음";
        age = 0;
        score = 0;
    }

    Student(String name) {
        this.name = name;
        age = 0;
        score = 0;
    }

    Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
}

위 코드에서는 Student 생성자가 세 개 있습니다. 매개변수 개수가 다르기 때문에 생성자 오버로딩이 가능합니다.

13. 생성자 오버로딩 사용 예제

생성자 오버로딩을 사용하는 전체 예제를 보겠습니다.

public class Main {
    public static void main(String[] args) {
        Student student1 = new Student();
        Student student2 = new Student("건");
        Student student3 = new Student("자바", 21, 95);

        student1.printInfo();
        student2.printInfo();
        student3.printInfo();
    }
}

class Student {
    String name;
    int age;
    int score;

    Student() {
        name = "이름 없음";
        age = 0;
        score = 0;
    }

    Student(String name) {
        this.name = name;
        age = 0;
        score = 0;
    }

    Student(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    void printInfo() {
        System.out.println("이름: " + name + ", 나이: " + age + ", 점수: " + score);
    }
}

실행 결과는 다음과 같습니다.

이름: 이름 없음, 나이: 0, 점수: 0
이름: 건, 나이: 0, 점수: 0
이름: 자바, 나이: 21, 점수: 95

객체를 생성할 때 전달하는 값의 개수에 따라 서로 다른 생성자가 호출됩니다.

14. 생성자와 메서드의 차이

생성자는 메서드와 비슷해 보이지만 목적과 규칙이 다릅니다.

구분 생성자 메서드
목적 객체 생성 시 초기화 특정 기능 수행
이름 클래스 이름과 같아야 함 자유롭게 작성 가능
반환타입 작성하지 않음 void, int, String 등 작성
호출 시점 new로 객체 생성 시 자동 호출 메서드 이름으로 직접 호출
호출 예 new Student() student.printInfo()

15. 생성자에서 기본값 넣기

생성자는 객체가 만들어질 때 기본값을 넣는 용도로도 사용할 수 있습니다.

class Account {
    String owner;
    int balance;

    Account(String owner) {
        this.owner = owner;
        this.balance = 0;
    }

    void printInfo() {
        System.out.println(owner + "님의 잔액: " + balance);
    }
}

위 코드에서는 계좌 주인 이름은 전달받고, 잔액은 기본값 0으로 설정합니다.

Account account = new Account("건");
account.printInfo();

실행 결과는 다음과 같습니다.

건님의 잔액: 0

16. 생성자에서 유효성 검사하기

생성자에서는 객체를 만들 때 들어오는 값이 올바른지 간단히 검사할 수도 있습니다.

class Student {
    String name;
    int score;

    Student(String name, int score) {
        this.name = name;

        if (score < 0) {
            this.score = 0;
        } else if (score > 100) {
            this.score = 100;
        } else {
            this.score = score;
        }
    }

    void printInfo() {
        System.out.println(name + "의 점수: " + score);
    }
}

점수가 0보다 작으면 0으로, 100보다 크면 100으로 저장하도록 처리했습니다.

17. 생성자 사용 시 자주 하는 실수

생성자를 처음 배울 때는 아래와 같은 실수를 자주 합니다.

실수 문제점 해결 방법
생성자에 void 작성 생성자가 아니라 일반 메서드가 됩니다. 생성자에는 반환타입을 작성하지 않습니다.
생성자 이름이 클래스 이름과 다름 생성자로 인식되지 않습니다. 생성자 이름은 클래스 이름과 같게 작성합니다.
매개변수 생성자만 만들고 기본 생성자 호출 new Student() 호출 시 오류 발생 기본 생성자가 필요하면 직접 작성합니다.
this 누락 필드에 값이 제대로 저장되지 않을 수 있습니다. this.name = name; 형태로 작성합니다.
생성자를 직접 호출하려고 함 생성자는 일반 메서드처럼 호출하지 않습니다. new로 객체를 만들 때 호출됩니다.

18. 직접 연습해보기

아래 코드를 직접 작성하고 실행해보세요.

public class Main {
    public static void main(String[] args) {
        Book book1 = new Book();
        Book book2 = new Book("자바 개념노트", 15000);
        Book book3 = new Book("스프링 입문", "GWDEVELBlog", 20000);

        book1.printInfo();
        book2.printInfo();
        book3.printInfo();
    }
}

class Book {
    String title;
    String author;
    int price;

    Book() {
        title = "제목 없음";
        author = "저자 없음";
        price = 0;
    }

    Book(String title, int price) {
        this.title = title;
        this.author = "저자 없음";
        this.price = price;
    }

    Book(String title, String author, int price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    void printInfo() {
        System.out.println("제목: " + title + ", 저자: " + author + ", 가격: " + price);
    }
}

실행 결과는 다음과 같습니다.

제목: 제목 없음, 저자: 저자 없음, 가격: 0
제목: 자바 개념노트, 저자: 저자 없음, 가격: 15000
제목: 스프링 입문, 저자: GWDEVELBlog, 가격: 20000

19. 이번 글 정리

이번 글에서는 객체 생성 시 자동으로 호출되는 생성자에 대해 정리했습니다. 핵심 내용은 다음과 같습니다.

  • 생성자는 객체가 생성될 때 자동으로 호출되는 특별한 메서드이다.
  • 생성자는 주로 객체의 필드 값을 초기화할 때 사용한다.
  • 생성자 이름은 클래스 이름과 같아야 한다.
  • 생성자에는 반환타입을 작성하지 않는다.
  • void도 생성자에는 작성하지 않는다.
  • 생성자를 작성하지 않으면 자바가 기본 생성자를 자동으로 제공한다.
  • 생성자를 하나라도 직접 작성하면 기본 생성자는 자동 제공되지 않는다.
  • 매개변수가 있는 생성자를 사용하면 객체 생성 시 값을 바로 전달할 수 있다.
  • this는 현재 객체의 필드를 가리킬 때 사용한다.
  • 생성자도 매개변수 차이에 따라 오버로딩할 수 있다.

한 줄 요약
생성자는 객체를 만들 때 자동으로 실행되어 필드 값을 초기화해주는 특별한 메서드입니다.

다음 글 예고
다음 글에서는 [Java 개념노트 23] this 키워드 이해하기라는 주제로 현재 객체를 가리키는 this의 의미와 사용법을 자세히 정리해보겠습니다.

GWDEVELBlog Java 개념노트 시리즈