개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

기초개념 › Java

생성자

생성자는 무엇이고, 언제 실행되는가

생성자는 클래스 안에 적는 코드 묶음입니다. 이름이 클래스 이름과 같고 반환 타입을 적지 않는다는 점이 메서드와 다릅니다. 메서드는 우리가 이름으로 불러야 실행되지만, 생성자는 new Card("김철수")를 실행할 때마다 한 번씩 실행되어 새로 만든 객체의 필드를 채웁니다. 생성자를 하나도 적지 않으면 컴파일러가 아무 일도 하지 않는 생성자를 대신 넣습니다. 이 실습은 Card(String owner) 생성자를 지우거나 객체를 만드는 줄을 new Card()로 바꿔 가며 같은 코드를 컴파일하고 실행해, 컴파일러가 무엇을 알려 주고 생성자가 몇 번 실행되는지를 봅니다.

실행으로 대조 · JDK 21에서 여덟 가지 조합을 javax.tools로 컴파일하고 실행해 대조

이 실습에 나오는 개념

생성자
객체를 new로 만들 때 한 번 실행되어 필드를 처음 상태로 맞추는 코드다. 이름이 클래스 이름과 같고 반환 타입을 적지 않는다. 받는 인자가 다르면 한 클래스에 여러 개를 둘 수 있으며, new에 넘긴 인자에 맞는 것이 선택된다. 생성자 본문은 필드가 기본값으로 채워지고 필드 초기화식과 초기화 블록이 실행된 뒤에 실행된다.
기본 생성자
클래스에 생성자를 하나도 적지 않았을 때 컴파일러가 자동으로 넣어 주는, 인자가 없고 본문이 빈 생성자다. 이것 덕분에 생성자를 적지 않은 클래스도 new 클래스이름()으로 객체를 만들 수 있다. 생성자를 하나라도 직접 적으면 만들어지지 않는다. 그래서 인자 있는 생성자만 적은 클래스는 인자 없이 new를 하면 컴파일 오류가 난다.
this
인스턴스 메서드나 생성자 안에서 지금 다루고 있는 객체 자신을 가리키는 참조다. this.name처럼 써서 같은 이름의 매개변수와 필드를 구분한다. 생성자의 첫 문장으로 this(인자)를 쓰면 같은 클래스의 다른 생성자를 먼저 실행한다. static 메서드에는 대상 객체가 없으므로 this를 쓸 수 없다.
필드의 기본값
객체가 만들어질 때 값을 따로 주지 않은 필드에 자동으로 들어가는 값이다. int 같은 숫자 타입은 0, boolean은 false, String을 비롯한 참조 타입은 null이다. 필드 초기화식이나 생성자가 값을 넣기 전까지는 이 값이 보인다. 메서드 안의 지역 변수에는 기본값이 없어서, 값을 넣지 않고 읽으면 컴파일 오류가 난다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. 컴파일러가 소스를 위에서부터 읽습니다. class Card 안에 Card(String owner)가 있습니다. 클래스와 이름이 같고 앞에 반환 타입이 없으므로 이것이 생성자입니다. String 값 하나를 받도록 적혀 있습니다.
  2. 컴파일러가 Main의 Card a = new Card("김철수"); 줄을 확인합니다. new로 객체를 만들 때는 넘긴 값에 맞는 생성자가 Card에 있어야 합니다. String 값 하나를 넘겼고, Card(String owner)가 String 값 하나를 받으므로 맞습니다.
  3. 컴파일이 성공해 실행할 Main 클래스 파일이 만들어집니다. 넘긴 값에 맞는 생성자가 있는지는 실행할 때가 아니라, 지금 컴파일러가 컴파일하면서 확인했습니다.
  4. java Main으로 실행합니다. main이 시작되고, Card a = new Card("김철수"); 줄에서 new를 만나면 자바가 먼저 새 Card 객체를 만듭니다. 이 객체의 owner에는 아직 아무 값도 들어가지 않아 비어 있습니다(null).
  5. 이어서 자바가 Card 생성자를 실행합니다. 우리가 쓴 코드에는 생성자를 부르는 줄이 없습니다. 생성자를 실행시킨 것은 new입니다. 넘긴 "김철수"가 매개변수 owner에 담깁니다.
  6. 생성자 안의 System.out.println("생성자 실행")이 실행되어 "생성자 실행"이 출력됩니다. 이 줄은 new를 할 때마다 생성자가 실행되는 것을 눈으로 보려고 넣었습니다.
  7. this.owner = owner가 실행됩니다. this는 지금 만들어지는 그 객체입니다. 매개변수 owner에 담긴 "김철수"가 그 객체의 필드 owner에 옮겨 담깁니다. 이름이 같은 필드와 매개변수를 this.owner(필드)와 owner(매개변수)로 구분합니다. 생성자가 끝나면 변수 a가 이 객체를 가리킵니다.
  8. System.out.println(a.owner)가 실행됩니다. a가 가리키는 객체의 owner에 든 "김철수"가 출력됩니다.

실행 결과

코드

class Card {
    String owner;
    // 생성자: 클래스와 이름이 같다. new Card(...)를 할 때 실행된다
    Card(String owner) {
        System.out.println("생성자 실행");
        this.owner = owner;
    }
}

public class Main {
    public static void main(String[] args) {
        Card a = new Card("김철수");
        System.out.println(a.owner);
    }
}

이 모형의 전제

컴파일러와 실행 환경은 JDK 21.0.12.1(javac 21)입니다. 여덟 가지 조합을 모두, 화면의 코드와 같은 소스(줄 단위로 같은 글)를 javax.tools로 컴파일하고, 컴파일에 성공한 것은 클래스 파일을 새 클래스 로더로 읽어 Main.main을 실행해 표준 출력을 잡은 결과와 대조했습니다. 대조한 것은 컴파일 성공 여부, 첫 번째 오류의 진단 코드(compiler.err.cant.apply.symbol)와 메시지에 적힌 필요한 인자와 넘긴 인자(화면의 두 가지 오류 설명으로 옮겼습니다), 오류의 개수와 오류가 난 줄, Main 클래스 파일이 만들어졌는지, 실행했을 때의 출력, 그리고 출력에서 "생성자 실행" 줄을 센 횟수입니다. 생성자를 적지 않은 조합은 우리가 쓴 생성자가 없으므로 실행 횟수를 0번으로 적었습니다. 단계 문장이 기대는 사실도 따로 실행해 확인했습니다. 생성자를 적지 않은 Card의 클래스 파일에는 매개변수 없는 생성자가 하나 들어 있고, 값을 받는 생성자를 적은 Card에는 그 생성자 하나뿐이며, 생성자 본문이 시작될 때 새 객체의 owner는 이미 null이고 매개변수에는 넘긴 값이 들어 있으며, new가 끝나야 main의 다음 줄이 실행됩니다. 생성자를 a.Card("이영희")나 Card("이영희")처럼 이름으로 부르는 줄은 컴파일 오류(cannot find symbol)였습니다. 문서는 Java Language Specification(Java SE 21)을 WebFetch로 열어 확인했습니다. 생성자의 이름이 클래스의 단순 이름과 같아야 하고 메서드와 달리 반환 타입이 없으며 메서드 호출식으로 부를 수 없다는 것은 8.8절, 생성자를 하나도 적지 않은 클래스에만 매개변수 없는 기본 생성자가 암묵적으로 선언된다는 것은 8.8.9절, 컴파일할 때 넘긴 인자에 맞는 생성자를 고르며 맞는 것이 없으면 컴파일 오류라는 것은 15.9.3절, 실행할 때 객체를 만들고 필드를 기본값으로 채운 뒤 인자를 계산하고 생성자를 실행한다는 것은 15.9.4절, 생성자 안에서 this가 지금 만들어지는 객체를 뜻한다는 것은 15.8.3절을 따랐습니다. 오류의 종류, 개수, 어느 줄에서 나는지는 명세가 정한 것이 아니라 이 javac에서 관찰한 것입니다. 오류가 여럿이면 javac는 모두 알리는데, 표에는 첫 번째 것만 적었습니다. 컴파일에 실패하면 Main 클래스 파일은 한 번도 만들어지지 않았고, 그래서 실행할 수 없다고 적었습니다. 화면의 코드는 Card 클래스를 package-private으로 두고 import 줄이 필요 없는 모양입니다. 생성자를 여러 개 두는 것(오버로딩), this(...)로 다른 생성자를 부르는 것, 상위 클래스 생성자 super(...), 필드 초기화식과 생성자의 실행 순서는 이 실습에서 다루지 않았고 "세부 동작 실습: 생성자"에서 다룹니다.

앞 실습: null · 다음 실습: static

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요