코틀린의 value class

토마스·2023년 2월 27일
0

로또 미션 중 로또 번호를 표현하는 클래스로

data class LottoNumber(private val number)

이렇게 만들었더니, 리뷰어님께서 value class를 사용하는 것이 어떻냐는 리뷰를 남겨주셨다. 그래서 value class에 대해 알아보았다.

value class란?

코틀린에서 원시값을 감싸는 클래스를 만들고 그 클래스의 객체를 사용하는 코드를 컴파일러가 원시값으로 변환해줘서 성능 향상할 수 있도록 도움을 주는 클래스의 종류이다.
함수의 인자로 넘겨줄 때 보통의 객체는 힙 영역에 저장된 객체의 주소를 넘겨주지만, value class는 객체의 주소가 아닌 값 그 자체를 넘겨준다. 따라서 힙 영역에 객체를 저장할 필요가 없기 때문에 객체를 생성하는 데 드는 시간을 아낄 수 있고, 힙 영역의 공간 또한 절약할 수 있다.
당연하지만, 컴파일 할 때 원시값으로 사용하기 위한 용도이기 때문에 value class의 주생성자의 매개변수는 한 개여야 한다.

정말 value class의 메소드를 사용하면 원시값으로 넘겨주는가?

아래는 생성자를 java로 디컴파일한 코드이다.

생성할 때 실행되는 init이 컴파일 되면 constructor_impl(int number)라는 메소드를 대신 실행하도록 함으로써 원시값을 객체로 만들지 않도록 한다.

다른 함수들 또한 원시값을 객체로 만들지 않도록 한다.
참고로 box_impl이라는 메소드는 LottoNumber클래스로 박싱해주는 함수이다. 만약 원시값이 아닌 객체가 필요한 함수의 인자로 넘겨줄 때 박싱해줘야 하는데 이 때 사용되는 메소드이다.

다른 클래스에서 LottoNumber 타입의 매개변수를 사용하는 메소드 또한 컴파일 되면 원시값으로 받는다.

Test 객체의 test 메소드를 실행하는 코드는 컴파일 되면 test_PDTtpoI(int number)를 실행하게 된다.

value class의 메서드는 inline 함수처럼 함수 호출에 대한 비용도 절약하는가?

아니다. value class의 메서드를 실행하는 코드는 컴파일 되면 value class의 정적 메소드를 실행하도록 한다. 따라서 함수를 실행하기 위해 스택 프레임을 만드느라 소모되는 자원을 절약하기 위해서는 inline 함수를 사용해야 한다.

value class가 인터페이스를 구현하면 어떻게 되는가?

나는 LottoNumber클래스를 비교할 수 있도록 하기 위해 Comparable<LottoNumber>를 구현하도록 했다.
아래는 LottoNumber의 compareTo 메소드를 java로 디컴파일한 코드이다.

compareTo 메소드를 보면

return this.compareTo-PDTtpoI(((LottoNumber)var1).unbox-impl());

라는 코드가 보인다. this라는 키워드는 생성된 객체를 가리키는 키워드이다. 즉, LottoNumber 객체를 생성해야 compareTo 메소드를 사용할 수 있다는 것이다. 인터페이스를 구현한 value class의 오버라이딩한 메소드를 사용할 때 박싱된다는 것은 이 글을 봐도 알 수 있다.

결론

  • 원시값 하나를 래핑하는 클래스를 만들 땐 value class를 사용하도록 하자.
  • 만약 value class가 인터페이스를 구현한다면 인터페이스를 구현한 메소드를 사용할 때는 박싱하기 위해 객체를 생성한다는 것을 알고 쓰자.
profile
안드로이드 개발자 지망생

0개의 댓글