Java

[Java] 생성자

콩스프 2022. 11. 26. 23:27
생성자 (Constructor) : new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당
  • 객체 초기화 : 필드를 초기화하거나, 메소드를 호출해서 객체를 사용할 준비를 하는 것
  •  생성자를 실행시키지 않고는 클래스로부터 객체를 만들 수 없음 
  • new 연산자에 의해 생성자가 성공적으로 실행되면 힙(heap) 영역에 객체가 생성되고 객체의 주소가 리턴
  • 리턴된 객체의 주소는 클래스 타입 변수에 저장되어 객체에 접근할 때 이용

* 생성자가 성공적으로 실행되지 않고 예외(에러)가 발생하면 객체는 생성되지 않음

 

 

기본 생성자

  • 모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있음
  • 클래스 내부에 생성자 선언을 생략
    ➡ 컴파일러가 중괄호 { } 블럭 내용이 비어있는 기본 생성자 (Default Constructor)를 바이트 코드에 자동 추가
  • 클래스가 public class로 선언되면 기본 생성자에도 public이 붙음
  • 클래스가 public class 없이 class로만 선언되면 기본 생성자에도 public이 붙지 않음
[public] 클래스() { }

 

💡 단, 클래스에 명시적으로 선언한 생성자가 한 개라도 있으면, 컴파일러는 기본 생성자를 추가하지 않음

 * 명시적으로 생성자를 선언하는 이유는 객체를 다양하게 초기화하기 위해서!

 

 


 

생성자 선언

  • 명시적 생성자 선언
클래스 ( 매개변수 선언, ... ) {
	//객체의 초기화 코드
}

 

  • 생성자는 메소드와 비슷한 모양을 가지고 있지만 리턴 타입이 없고 클래스 이름과 동일
  • 생성자 블록 내부 : 객체 초기화 코드
    1) 필드에 초기값 저장
    2) 메소드를 호출하여 객체 사용 전 필요한 준비
  • 매개 변수 선언은 생략할 수도 있고, 여러 개를 선언할 수 있음
  • 매개 변수는 new 연산자로 생성자를 호출할 때 외부의 값을 생성자 블록 내부로 전달하는 역할을 함

생성자 EX)

Car myCar = new Car("그랜져", "검정", 300);
  • 두 개의 매개값은 String 타입이고 마지막 매개 값은 int 타입인 것을 볼 수 있음
public class Car {
	//생성자
    Car(String model, String color, int maxSpeed) { 
    	...
    }
}
  • 세 매개값을 생성자가 받도록 선언

 

 

  • 클래스에 생성자가 명시적으로 선언되어 있을 경우 반드시 선언된 생성자를 호출해서 객체를 생성해야 함

명시적 생성자 호출 EX)

//[Car.java]
public class Car {
	//생성자
    Car(String color, int cc){
    	...
    }
}

 

//[CarExample.java]
public class CarExample {
	public static void main(String[] args) {
    	Car myCar1 = new Car("검정", 3000);
        Car myCar2 = new Car(); //(X) 기본생성자를 호출할 수 없음.
    }
}

  • Car 클래스에 생성자 선언이 있기 때문에 기본생성자 Car()를 호출해서 객체를 생성할 수 없음
  • Car(String color, int cc) 를 호출해서 객체를 생성해야 함

 

 


 

필드 초기화

  • 클래스로부터 객체가 생성될 때 필드기본 초기값으로 자동 설정
  • 다른 값으로 초기화를 하는 방법은 두 가지가 있음

 

1) 필드를 선언할 때 초기값을 주는 법

  • 동일한 클래스로부터 생성되는 객체들이 모두 같은 데이터를 갖게 됨
  • 객체 생성 후 변경할 수 있지만 객체 생성 시점에는 필드의 값이 모두 같음

필드 선언시 초기화 EX)

public class Korea {
    String nation = "대한민국";
    String name;
    String ssn;
}
  • Korean 클래스에 nation 필드를 선언하면서 "대한민국"으로 초기값을 줌

 

public static void main(String[] args) {
    Korean k1 = new Korean();
    Korean k2 = new Korean();	
}
  • Korean 클래스로부터 k2과 k2 객체를 생성하면 k1과 k2 객체의 nation 필드에는 모두 "대한민국"이 저장됨

 

 

2) 생성자에서 초기값을 주는 방법

  • 객체 생성 시점외부에서 제공되는 다양한 값들로 초기화 되어야 한다면 생성자에서 초기화를 해야 함
  • 객체의 필드는 하나가 아니라 여러 개가 있음
  • 필드들을 모두 생성자에서 초기화한다면 생성자 매개 변수의 수는 객체의 필드 수만큼 선언되어야 함
    ➡ 실제로는 중요한 몇 개 필드만 매개 변수를 통해 초기화
     나머지 필드들은 선언 시에 초기화 하거나 생성자 내부에서 임의의 값 또는 계산된 값으로 초기화
    ➡ 객체 생성 후 필드 값을 별도로 저장하기도 함

 

생성자에서의 초기화 EX)

Public class Korean {
    //필드
    String nation = "대한민국";
    String name;
    String ssn;
    
    //생성자
    public Korean(String n, String s) {
    	name = n;
        ssn = s;
    }
}
  • name(이름)과 ssn(주민번호) 필드값은 클래스를 작성할 때 초기값을 줄 수 없음
  • 객체 생성 시점 다양한 값을 가져야 함 ➡ 생성자의 매개값으로 값들을 받아 초기화하는 것이 맞음

 

Korean k1 = new Korean("김철수", "990101-1234567");
Korean k2 = new Korean("박영희", "991231-2987654");
  • "김철수"와 "박영희"는 매개 변수 n을 통해 전달됨
  • "990101-1234567"과 "991231-2987654"는 매개 변수 s를 통해 전달됨
  • 이 값들은 각각 name 필드와 ssn 필드의 초기값으로 사용됨

 


 

this

  • 생성자의 매개 변수 이름이 너무 짧으면 코드 가독성이 좋지 않음
  • 초기화시킬 필드 이름과 비슷하거나 동일한 이름을 사용하는 것이 좋음
  • 관례적으로 필드와 동일한 이름을 갖는 매개 변수를 사용

    문제점)
    필드와 매개변수 이름이 동일하기 때문에 생성자 내부에서 해당 필드에 접근할 수 없음
    ➡ 동일한 이름의 매개 변수가 사용 우선순위가 높기 때문

    해결방법)
    필드 앞에 this. 를 붙임

 

this : 객체 자신의 참조
  • 우리가 우리 자신을 "나"라고 하듯 객체가 객체 자신을 this라고 함
  • this.필드 는 this라는 참조 변수로 필드를 사용하는 것과 동일

 

this 사용 EX)

public Korean(String name, String ssn) {
    this.name = name;	//this.name은 필드, name은 매개변수
    this.ssn = ssn;	//this.ssn은 필드, ssn은 매개 변수
}