6-5. 생성자

Hyun Jun·2022년 1월 22일
0

자바의 정석

목록 보기
24/52
post-thumbnail
post-custom-banner

생성자

생성자의 정의

생성자 == 인스턴스 초기화 메서드

  • 인스턴스가 생성될 때 호출되어, 인스턴스 변수를 초기화해주는 역할

  • 리턴 값이 없으나 void라고 명시하지 않음

  • 이름은 클래스의 이름과 같음

  • 오버로딩 가능 (한 클래스에 여러개의 생성자가 존재할 수 있음)

 

클래스명 (타입 변수명1, 타입 변수명2, ...) {
    // 인스턴스 생성 시 수행될 코드 (인스턴스 변수 초기화 등)
}
class Rectangle {
    Rectangle() {
        // ...
    }
    Rectangle(int width, int height) {
       // ...
    }
    // ...
}
Rectangle r = new Rectangle(4, 5);

연산자 new가 인스턴스를 생성해주고, 그 뒤에 붙는 "클래스명()"이 생성자 함수로서 인스턴스 초기화를 진행함.

인스턴스를 생성할 때에는 클래스에 정의되어 있는 생성자 중의 하나를 선택하여 사용해야함.

 

기본 생성자

모든 클래스에는 하나 이상의 생성자가 정의되어 있어야함.

생성자가 없는 경우, 암묵적으로 컴파일러가 기본 생성자를 만들어줌.

클래스명() {}
Rectangle() {}

이처럼 매개변수도 없고 블럭 안의 내용도 비어있는 간단한 형태.

 

class Test1 {
    int value;
    // 생성자가 없으므로 인스턴스를 생성할 때 기본 생성자가 추가됨
}

class Test2 {
    int value;
    Test2 (int x) {
        value = x; // 인스턴스 변수 value를 생성자의 매개변수로 받아온 값으로 초기화시켜줌
    }
    // 생성자가 있으므로 기본 생성자는 추가되지 않음
}

class ConstructorTest {
    public static void main(String[] args) {
        Test1 t1 = new Test1(); // (O) 기본 생성자 문법
        Test2 t2 = new Test2(); // (X) Test2는 기본 생성자 대신 따로 정의된 생성자가 있는데 매개변수를 요구하므로 이렇게 작성하면 에러 발생
    }
}

이전까지는 생성자의 개념을 몰랐으므로, 당연히 따로 생성자를 작성하지 않았고 항상 new Test1();와 같은 형태로만 써왔음

그러나 항상 그렇게 작성하는 것은 아니고, Test2에서처럼 생성자를 직접 정의한 경우에는 정의했던 생성자의 형식에 맞춰서 인스턴스를 초기화 시켜주어야함.

Test2 t2 = new Test2(3); // (O) 정의된 생성자의 스펙을 준수했음

 

매개변수가 있는 생성자

생성자가 넘겨받는 매개변수는 인스턴스 변수를 초기화하는데에 사용할 수 있음.

class Laptop {
    String brand;
    int screenSize;
    float weight;

    Laptop() {} // 생성자1
    Laptop(String b, int s, float w) {
        brand = b;
        screenSize = s;
        weight = w;
    } // 생성자2
}

만약 매개변수가 없는 생성자1을 사용하여 인스턴스를 생성하게 되면, 인스턴스 변수들은 생성 이후 각각 따로 초기화를 시켜주어야 함.

그러나 생성자2를 사용하면 인스턴스를 생성하는 즉시 인스턴스 변수의 값도 초기화 시켜줄 수 있음.

Laptop gram = new Laptop(); // 별도의 인스턴스 변수 초기화 필요
Laptop macbook = new Laptop("Apple", 15, 1.8f); // 한방에 해결!

 

생성자에서 다른 생성자 호출하기

2가지 조건만 만족한다면 생성자들끼리도 서로를 호출할 수 있음.

  • 생성자의 이름으로 클래스이름 대신 this 사용

    this는 참조변수로 인스턴스 자신을 가리킴.

  • 다른 생성자를 호출하는 것은 반드시 첫번째 줄에서만

    다른 생성자를 첫번째 줄 이후에 호출해버리면, 그전까지 진행중이던 초기화 작업들이 모두 무의미해질 수 있기 때문

    Laptop(String b) {
       screenSize = 15;
       Laptop(b, 13, 1.4f); // (X) 바로 윗줄에 초기화된 screenSize 값이 무시되고 새로 덮어씌워짐
    }
    • 예시에 등장한 두번째 생성자의 위치는 첫번째 줄이어야 맞음

    • 생성자에 클래스 이름 대신 this를 써야 맞음

    아래와 같이 고칠 수 있음

    Laptop(String b) {
       this(b, 13, 1.4f); // (O)
    }

 

class Laptop {
    String brand;
    int screenSize;
    float weight;

    // 생성자1
    Laptop() {
        this("Apple", 13, 1.4f); // 생성자3을 호출해서 3줄에 걸쳐 할 일을 1줄로 끝냄.
    }
    // 생성자2
    Laptop(String brand) {
        this(brand, 13, 1.4f);
    }
    // 생성자3
    Laptop(String brand, int screenSize, float weight) {
        this.brand = brand; // 매개변수로 선언된 변수의 이름이 인스턴스 변수의 이름과 같을 때는 구분을 위해 인스턴스 변수 앞에 this를 붙여줌.
        this.screenSize = screenSize;
        this.weight = weight;
    }
}

📌 [주의] thisthis()는 완전히 다른 의미임.

  • this: 인스턴스 자신을 가리키는 참조변수 (모든 인스턴스 내에 숨겨진 지역변수)

  • this(): 생성자 (같은 클래스 내 다른 생성자를 호출할 때 사용함)

 

생성자를 이용한 인스턴스의 복사

생성자의 매개변수에 인스턴스를 나타내는 참조변수를 넣으면, 참조변수로 접근하는 원본 인스턴스의 멤버들을 그대로 복제하여 새 인스턴스에 똑같이 할당해줄 수 있음

Laptop(Laptop laptop) {
    brand = laptop.brand;
    screenSize = laptop.screenSize;
    weight = laptop.weight;
}

이제 이 생성자로 만드는 새 인스턴스는 매개변수에 담긴 인스턴스와 같은 값들을 가짐.

그래도 객체 주소는 다르고, 따라서 원본에서 값이 변경되어도 복제본에는 반영이 안됨 (반대의 경우도 마찬가지)

 

앞으로 인스턴스를 생성할 때는 다음 2가지 고민을 해봐야함.

  1. 어떤 클래스의 인스턴스를 생성할 것인지

  2. 선택한 클래스에서 어떤 생성자를 사용하여 인스턴스를 생성할 것인지

profile
Back-end Engineer 👨‍💻
post-custom-banner

0개의 댓글