본문 바로가기

카테고리 없음

[Java] 기본 생성자가 필요한 '진짜' 이유 (리플렉션 오해 바로 잡기!!!)

'기본 생성자가 필요한 이유'라고 검색해보면 여러 블로그에서 하나같이 하는 소리가 있다.

 

기본 생성자가 필요한 이유는 Reflection API로 가져올 수 없는 정보 중 하나가
생성자의 인자 정보이기 때문
이다.

 

아.. 안돼..!

나도 처음엔 진짜 그런줄 알았다. 이 내용 그대로 테코톡 발표까지 할뻔했으니.. 기본 생성자가 필요한 '진짜' 이유를 알아보기 전에 간단히 리플렉션이 뭔지부터 알아보도록 하자. 리플렉션이 뭔지 궁금하지 않다면 넘어가도 좋다.

 

리플렉션이란?

 

리플렉션을 한글로 번역하면 '거울에 비친 상, 모습'이라는 의미이다.

 

우리가 거울을 통해 내 모습을 확인하는 것처럼 실체가 아닌 거울에 반사, 반영된 이미지를 통해 어떠한 행위를 하는 것이 리플렉션이라 볼 수 있겠다. 그렇다면 자바 세상에서는 무엇이, 어디에 반사되어 있는 걸까?

자바에서는 실체가 클래스, 거울이 JVM 메모리 영역이라 생각하면 편하다. 클래스 정보가 JVM 내의 메모리 영역에 저장되고, 이 클래스 정보를 '리플렉션'이라는 기능을 통해 다시 가져와서 유용하게 사용할 수 있다. 

 

리플렉션이 더 궁금하다면? 나와 아키의 리플렉션 테코톡을 보고오자.

리플렉션을 왜 쓸까?

아니 근데, 내가 직접 코드를 작성했다면 클래스 정보를 모를 수가 없지 않나? 클래스 정보를 왜 굳이 번거롭게 '리플렉션'이라는 어려운 기능까지 사용해가면서 가져와야 할까?

맞다. 우리가 직접 코드를 작성할 때는 객체의 타입을 모를 일이 거의 없다. 반면 프레임워크나 라이브러리에서는 사용자가 어떤 클래스를 만들지, 객체의 타입이 뭔지 컴파일 시점에 알 수 없다. 이를 동적으로 해결하기 위해 리플렉션을 사용하는 것이다.

 

JPA, Jackson, Mockito, JUnit 등 정말 많은 곳에서 리플렉션을 사용하고 있다. 이런 프레임워크, 라이브러리들을 사용하다 보면 객체에 기본 생성자를 요구하는 경우가 많다. 왜 때문일까?

 

리플렉션으로 생성자의 인자(파라미터) 정보를 가져올 수 없다는 오해

기본 생성자가 필요한 이유는 Reflection API로 가져올 수 없는 정보 중 하나가
생성자의 인자 정보이기 때문
이다.

 

일단 이 오해부터 풀어보자. 진짜 리플렉션으로 생성자의 인자(파라미터) 정보를 가져올 수 없을까?

 

자 실험을 위해 'Dog' 클래스에 파라미터가 다른 세 개의 생성자를 민들어 놓았다. 리플렉션을 통해 파라미터 정보를 가져와보자.

 

 

이렇게 테스트 코드를 작성해서 실행해보았다.

 

 

!?!? 예상과는 다르게 생성자의 파라미터 정보를 너무 쉽게 가져올 수 있음을 확인했다. 그럼 왜 '리플렉션을 통해 생성자의 인자 정보를 가져올 수 없다'는 헛소문(?)이 퍼지게 된걸까? 이렇게 추측하고 있다.

1.  java7까지는 파라미터 정보를 가져올 수 없었다.

 

리플렉션의 Parameter는 java8에서 추가되었다. 그 전에는 리플렉션을 통해 파라미터 정보를 가져올 수 없었다는 것이 맞다.

2. 지금도 파라미터 이름을 가져오려면 컴파일 옵션을 추가해야 한다.

그렇지 않으면.. 파라미터 이름이 arg0, arg1 이렇게 나온다.

 

그럼에도 기본 생성자가 필요한 이유

 

현재는 파라미터 정보를 쉽게 가져올 수 있음에도 기본생성자를 요구하는 이유를 나는 이렇게 추측하고 있다. 

 

기본 생성자로 객체를 생성하고 필드를 통해 값을 넣어주는 것이 가장 간단한 방법이기 때문이다.

 

그 이유를 세 가지로 나눠 더 자세히 살펴보자.

 

1. 어떤 생성자를 사용할지 고르지 어렵다.

이렇게 생성자 종류가 많은 경우, 기본생성자를 사용하지 않으면 프레임워크나 라이브러리가 어떤 생성자를 사용할지 판단하기 어렵다.

 

2. 생성자에 로직이 있는 경우 원하는 값을 바로 넣어줄 수 없다.

강아지의 나이를 10으로 넣어주고 싶었는데 모종의 이유로 생성자에 +1 로직이 있다면? 원하는 값을 바로 넣어주기 힘들 것이다.

 

3. 파라미터들의 타입이 같은 경우 필드와 이름이 다르면 값을 알맞게 넣어주기 힘들다.

예시처럼 파라미터의 타입이 겹치는 데에다, 필드와 이름까지 다르면 어디에 어떤 값을 넣어줘야 할지 프레임워크/라이브러리가 판단할 수 있을까?

 

기본 생성자를 이용한다면 이 모든 경우의 수들을 고려하지 않아도 된다. 그저 기본 생성자로 객체를 생성하고, 필드 이름에 맞춰 원하는 값을 넣어주면 끝인 것이다. 이렇게 기본 생성자를 사용하는 것이 사용하지 않는 것보다 훨씬 간단하기 때문에 많은 프레임워크나 라이브러리에서 기본 생성자를 강제하고 있는 것으로 추측한다.

 

물론 이것들도 나의 뇌피셜이다. 이 글을 보는 여러분들도 블로그의 말을 쉽게 믿지 말고 항상 의심하고 또 고민하자..! 더 좋은 의견 있으면 댓글로 알려주시라. 그럼 이만~