이전에 팀프로젝트 할 때도 그렇고 이번에 JPA를 사용해서 공부하던 도중 기본 생성자가 없어서 에러가 발생.
"도대체 왜 기본 생성자가 필요한걸까?" 의문이 생김.
이랬던 적이 한 두번이 아니라 관련내용을 정리를 한 글.
1. 기본 생성자.
public 클래스이름() {
}
기본 생성자(Default Constructor)
- 매개변수가 없는 생성자를
기본 생성자라 함.
- 생성자가 하나도 없을 경우 자바 컴파일러가
매개변수가 없고 {}안 아무것도 없는 기본 생성자를 자동으로 만들어줌. (생략되어 있음.)
- 단, 생성자가 하나라도 있다면 기본 생성자가 생성되지 않음.
- 자동으로 생성된 기본 생성자는 클래스와 같은 접근 제어자를 가짐.
2. Reflection API
Reflection API란?
Reflection API는 클래스의 구체적인 타입을 알지 못해도 해당 클래스의 메서드, 필드, 생성자 등의 정보를 런타임에 동적으로 가져오거나 접근할 수 있는 Java API.
- 접근 제어자와 상관 없이 클래스
객체를 동적으로 생성(런타임 시점).
- 이미 로딩이 완료된 클래스에서 또 다른 클래스를 동적으로 로딩(Dynamic Loading)하여 생성자(Constructor), 멤버 필드(Member Variables) 그리고 멤버 메서드(Member Method) 등을 사용할 수 있도록 함.
- 즉, 컴파일 시간(Compile Time)이 아니라 실행 시간(Run Time)에 동적으로 특정 클래스의 구조를 분석하고 활용할 수 있는 기능.
- 자바는 컴파일러를 사용하고, 컴파일 시점에 타입이 결정됨.
2-1. 원리.
- 자바에서는 JVM이 실행되면 코드가 컴파일러를 거쳐 바이트 코드로 변환되어
static 영역에 저장되는데 Reflection API는 이 정보를 활용함.
2-2. 단점.
성능 문제, 메모리 낭비.
- 컴파일 시점이 아닌 런타임에 동적으로 타입을 분석하고 정보를 가져오므로 JVM을 최적화할 수 없기 때문.
캡슐화, 추상화 깨지는 문제. (접근 제어자 무시)
2-3. 사용처.
- 프레임워크나 라이브러리에서 주로 사용됨.
- 프레임워크나 라이브러리는 사용자가 어떤 클래스를 만들지 예측할 수 없기 때문에 동적으로 해결해주기 위해 Reflection을 사용.
Ex intellij의 자동완성, jackson 라이브러리, Hibernate Spring Framework 등
- 스프링 프레임워크의 경우 대표적인 예시로 Spring Container의 BeanFactory.
- Bean은 애플리케이션이 실행한 후 런타임에 객체가 호출될 때 동적으로 객체의 인스턴스를 생성하는데 이때 Spring Container의 BeanFactory에서 리플렉션을 사용
3. JPA
JPA는 Entity로 사용할 객체에 반드시 기본 생성자가 있어야 됨.
- JPA 에서 Entity에 기본 생성자가 필요한 이유가
동적으로 객체 생성 시 Reflection API를 활용하기 때문임.
- 왜냐하면
Reflection API로 가져올 수 없는 정보 중 하나가 생성자의 인자 정보.
- 그래서
기본 생성자가 반드시 있어야 객체를 생성할 수 있음.
기본 생성자로 객체를 생성만 하면 필드 값 등은 Reflection API로 넣어줄 수 있음.
- 기본 생성자 없이 사용자가 만들어놓은 파라미터가 있는 생성자만 존재한다면 Java Reflection이 객체를 생성할 수 없게 됨.
4. 추가내용.
- Almost all frameworks require a default(no-argument) constructor in your class because these frameworks use reflection to create objects by invoking the default constructor
- 거의 모든 프레임워크는 클래스에 기본 생성자(인자가 없는 생성자)를 요구합니다.
이유는 이러한 프레임워크들이 기본 생성자를 호출하여 객체를 생성하기 위해 Reflection을 사용하기 때문입니다.
김영한님의 인프런 강의 : 자바 ORM 표준 JPA 프로그래밍.

- 이렇게 기본 생성자가 없더라도 실행되는 경우가 있는데 해당 질문에 대한 김영한님의 답변을 참고.

- 하이버네이트는 내부적으로 Class.newInstance()라는 리플렉션을 이용해 해당 Entity의 기본 생성자를 호출해서 객체를 생성하는데 이 리플렉션은 생성자의 매개변수를 읽을 수가 없어서 반드시 기본 생성자를 정의해야함.
- 항상 기본 생성자를 정의해야 하는 것은 아니고 아래의 코드처럼 매개변수가 있는 생성자를 정의했을 때만 기본 생성자를 생성해주면 됨.
public User(String name) {
this.name = name;
}
- 만약 매개변수가 있는 생성자를 정의하지 않았다면 자바에서 자동으로 기본 생성자를 생성하기 때문에 따로 기본 생성자를 정의하지 않아도 됨.
5. 기타.
-
컴파일 시점에 타입을 결정.(정적 언어) : Java, C, C++, Go 등등
- 컴파일 : 작성한 코드를 기계어로 변환하여 실행가능한 프로그램으로 변환시키는 과정을 컴파일, 컴파일이 이루어지는 시간을 컴파일 타임.
-
런타임 시점에 타입을 결정(동적 언어) : Python, PHP, JavaScript, Ruby 등등
- 런타임 : 컴파일이 끝난 프로그램이 실행되고, 이러한 응용프로그램이 실행되고 있는 걸 런타임(Runtime).
6. Ref