컴파일러는 개발자가 기본 생성자를 생성하지 않아도 알아서 생성해줍니다.
기본 생성자를 만드는 규칙은 다음과 같습니다.
- 생성자의 이름은 클래스의 이름과 동일하게 선언합니다.
- 리턴 타입은 없습니다.
- 매개 변수는 없습니다.
- 접근 제한자는 클래스를 따라갑니다.
다음은 기본 생성자의 예시입니다.
public class Car {
// 명시적으로 생성자를 선언하지 않으면,
// 자바 컴파일러가 개입 -> 기본 생성자 생성
Car(){
;;
} // default Constructor
} // end class
만약 롬복(lombok)이 설치되어 있다면 롬복으로 기본생성자를 만들 수 있습니다.
@Log4j2
@NoArgsConstructor // lombok으로 기본 생성자 생성
public class Car {
} // end class
하지만 기본 생성자 이외에 인자값을 받는 생성자가 필요한 상황이 있습니다.
@Log4j2
@NoArgsConstructor // 기본 생성자 생성
public class Car {
private String color; // 인스턴스 필드
private int cc;
Car(String color, int cc){
// 외부에서 인자값을 받아 인스턴스 필드 초기화
this.color = color;
this.cc = cc;
} // Constructor
} // end class
이렇게 외부에서 값을 받아 인스턴스 필드를 초기화할 때, 인자값을 받는 생성자를 생성합니다.
this는 객체의 레퍼런스(주소)를 가리키는 것입니다.
로그를 통해 알아보겠습니다.
@Log4j2
@NoArgsConstructor
public class Car {
private String color;
private int cc;
Car(String color, int cc){
log.trace("Car({}, {}) invoked", color, cc);
// 외부에서 인자값을 받아 필드 초기화
this.color = color;
this.cc = cc;
// Car 클래스에서의 this가 가리키는 주소를 로그로 출력
log.info("\t + myCar1 : {}",this);
} // Constructor
} // end class
// =====================================================
@Log4j2
public class CarExample {
public static void main(String[] args) {
log.trace("main({}) : invoked", Arrays.toString(args));
Car myCar1 = new Car("검정", 3000);
//CarExample 클래스에서 myCar1이 가리키는 주소를 로그로 출력
log.info("\t + this : {}", myCar1);
Car myCar2 = new Car();
} // main
} // end class
롬복의 log.info를 통해 출력하면 다음과 같은 주소가 출력됩니다.
12:18:09.971 INFO --- [ main] s.e.Car.<init>:23 - + this : sec07.exam01.Car@c333c60
12:18:09.971 INFO --- [ main] s.e.CarExample.main:15 - + myCar1 : sec07.exam01.Car@c333c60
@ 이후의 값을 보시면 Car 클래스의 this와 CarExample의 myCar1이 동일한 값을 가리키는 것을 알 수 있습니다.
즉, 객체의 주소를 저장하고 있는 것은 참조변수 뿐만 아니라 this 또한 객체의 주소를 저장하고 있습니다.
주의할 점은, static이 붙은 필드를 초기화할 때에는 오직 static initializer이 해야 합니다.
@Log4j2
@NoArgsConstructor // 기본 생성자 생성
public class Car {
private String color;
private int cc;
private static String company; // 정적 필드
static {
company = "현대";
} // static initializer, 정적 블록
Car(String color, int cc){
// 외부에서 인자값을 받아 필드 초기화
this.color = color;
this.cc = cc;
} // Constructor
} // end class
정적 필드는 해당 클래스에서 생성한 모든 인스턴스(객체)에 공유되는 필드입니다.
반면, 인스턴스 필드는 생성한 각 객체마다 가지고 있는 필드입니다.
정적 블록은 한번만 실행되며, static 필드(정적 필드)를 초기화하기 위해 사용됩니다.
여기서 클래스의 선언하는 멤버의 종류를 두 가지로 나눌 수 있습니다.
1. 인스턴스 필드와 인스턴스 메소드는 각각의 객체의 소속입니다.
2. 정적 필드와 정적 메소드는 "java.lang.Class" 타입의 객체(Clazz)라고 할 수 있습니다.
Clazz는 너무 추상적이라 이해가 안될수 도 있기 때문에, Clazz 객체를 구해보겠습니다.
구하는 방법은 세 가지가 잇습니다.
1. 참조타입명.class
2. 참조변수.class
3. java.lang.Class.forName("참조타입명"); => 리턴타입 : Clazz
코드로 구해보겠습니다.
@Log4j2
public class KoreanExample {
public static void main(String[] args) throws ClassNotFoundException{ // 3번 오류 던지기
log.trace("main({}) invoked", Arrays.toString(args));
1. 참조타입명.class
java.lang.Class clazz = Korean.class;
log.info("\t + 1st. clazz: {}", clazz);
2. 참조변수.getClass()
Korean korean = new Korean();
log.info("\t + 2nd. clazz : {}", korean.getClass());
3. java.lng.Class.forName("참조타입명"); => 리턴타입 : clazz
clazz = Class.forName("sec07.exam02.Korean");
log.info("\t + 3nd. clazz : {}", clazz);
} // main
} // end class
// ============================================
@Log4j2
@NoArgsConstructor
public class Korean {
} // end class
출력하면 다음과 같은 로그가 출력됩니다.
14:21:50.490 INFO --- [ main] s.e.KoreanExample.main:21 - + 1st. clazz: class sec07.exam02.Korean
14:21:50.491 INFO --- [ main] s.e.KoreanExample.main:24 - + 2nd. clazz : class sec07.exam02.Korean
14:21:50.491 INFO --- [ main] s.e.KoreanExample.main:27 - + 3nd. clazz : class sec07.exam02.Korean
정적 필드와 메소드에 대해서 동일한 clazz가 출력되는 것을 볼 수 있습니다.