Kotlin 기본 자료형(Primitive type)과 참조 자료형(Reference type)

기본 자료형과 참조 자료형

자바와 다르게 기본 자료형(Primitive type)과 참조 자료형(Reference type)이 구별하여 사용되지만, 코틀린에서는 자바와 다르게 Int, Long, Boolean 등과 같이 구별이 없이 사용된다.

그러면, 코틀린에서는 기본 자료형과 참조 자료형이 따로 없는 것인가? null 있다는 것을 감안해서 아래와 같이 2가지로 추측을 해 볼 수 있다.

  • 자료형에 null이 있으니 무조건 참조형으로 선언될 것이다.
  • 자료형이 null이 허용된다면 참조형, null이 허용되지 않는다면 기본형일 것이다.

먼저, 여기서 정답은 후자이다. 자료형이 null이 허용된다면 참조형으로 선언되고, null이 허용되지 않는다면 기본형으로 선언된다.
즉, JVM에서는 코틀린에서 데이터 타입을 어떻게 선언하였는냐에 따라 기본 자료형과 참조 자료형으로 변환이 된다.

그럼 예제 코드를 통해서 알아보도록 하자.
Kotlin

fun main() {
    val n1 = 10
    val n2: Int = 20
    val n3: Int? = 30

    println("n1=$n1, n2=$n2, n3=$n3")
}

위 코드에서는 아래 3가지 경우로 변수를 선언하였다.

  • Int이 선언되지 않은 경우
  • Int으로 선언되어 null을 허용하지 않는 경우
  • Int?으로 선언되어 null을 허용하는 경우

그럼 이를 바이트 코드로 변환하여 일부를 확인을 해보면 아래와 같다.
Bytecode

   L0
    LINENUMBER 4 L0
    BIPUSH 10
    ISTORE 0
   L1
    LINENUMBER 5 L1
    BIPUSH 20
    ISTORE 1
   L2
    LINENUMBER 6 L2
    BIPUSH 30
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    ASTORE 2

L1, L2에서는 각각 10, 20이 할당되는 것을 볼 수 있고, L2에서는 30이 할당되고 Integer.valueOf(int i)가 호출되어 참조형으로 반환되는 것을 볼 수 있다.

    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;

그럼 더 쉽게 Java로 디컴파일(Decompile)해서 코드를 살펴 보자.
Java

public final class DataTypePrimitiveReferenceTutorialKt {
   public static final void main() {
      int n1 = 10;
      int n2 = 20;
      Integer n3 = 30;
      String var3 = "n1=" + n1 + ", n2=" + n2 + ", n3=" + n3;
      boolean var4 = false;
      System.out.println(var3);
   }

   // $FF: synthetic method
   public static void main(String[] var0) {
      main();
   }
}

자료형이 Java에서는 다음 표와 같이 변형된 것을 볼 수 있다.

데이터 타입 선언 Kotlin 자료형 Java 자료형
var n1 = 10 Int int
var n2: Int = 20 Int int
var n3: Int? = 30 Int Integer

코틀린 자료형에 주의점

코틀린에서는 기본 자료형과 참조 자료형의 구별이 없다기 보다는 감춰져 있는 거라고 볼 수 있을 거 같다. 일반적으로는 자료형을 구별없이 사용해도 큰 무리가 없을 수 있지만, 코틀린에서 리플렉션을 활용한 자바 라이브러리는 호출하였을 시에 문제가 있을 수 있다.

아래 코드는 실제 자바 라이브러리(spring-retry)에서 발취한 코드인데, 여기서는 Parameter와 Argument에 대한 타입을 비교하고 있다.

if (!parameterTypes[i].isAssignableFrom(argument.getClass())) {
    return false;
}

Parameter가 int이고, Argument가 Integer가 되면 false가 반환하게 되어 사용자가 의도치 않게 동작을 하게 될 것이다.