Int, Boolean, Any 등의 원시 타입에 대해 살펴본다. 코틀린은 원시 타입과 래퍼 타입을 구분하지 않는다.

원시 타입 Int, Boolean 등

자바는 원시 타입(Primitive type)과 참조 타입(reference type)을 구분한다. 원시 타입(int 등)의 변수에는 그 값이 직접 들어가지만, 참조 타입(String 등)의 변수에는 메모리상의 객체 위치가 들어간다.

자바는 참조 타입이 필요한 경우 특별한 래퍼 타입(java.lang.Integer 등)으로 원시 타입 값을 감싸서 사용한다. 따라서 정수의 컬렉션을 정의하려면 Collection<int>가 아니라 Collection<Integer>를 사용해야 한다.

코틀린은 원시 타입과 래퍼 타입을 구분하지 않으므로 항상 같은 타입을 사용한다.

fun main() {
    val i: Int = 1
    val list: List<Int> = listOf(1,2,3)
}

코틀린에서는 숫자 타입 등 원시 타입의 값에 대해 메소드를 호출할 수 있다.

fun showProgress(progress: Int) {
    val percent = progress.coerceIn(0, 100)
    println("We're ${percent}% done!")
}
fun main() {
    showProgress(146) // We're 100% done!
}

실행 시점에 숫자 타입은 가능한 한 가장 효율적인 방식으로 표현된다. 대부분의 경우(변수, 프로퍼티, 파라미터, 반환 타입 등) 코틀린의 Int 타입은 자바 int 타입으로 컴파일된다. 이런 컴파일이 불가능한 경우는 컬렉션과 같은 제네릭 클래스를 사용하는 경우 뿐이다. 에를 들어 Int 타입을 컬렉션의 타입 파라미터로 넘기면 그 컬렉션에는 Int의 래퍼 타입에 해당하는 java.lang.Integer 객체가 들어간다.

자바 원시 타입은 다음과 같다.

Int와 같은 코틀린 타입에는 널 참조가 들어갈 수 없기 때문에 그에 상응하는 자바 원시 타입으로 컴파일할 수 있다.

널이 될 수 있는 원시 타입: Int?, Boolean? 등

코틀린에서 널이 될 수 있는 원시 타입을 사용하면 그 타입은 자바의 래퍼 타입으로 컴파일된다.

data class Person(val name: String, val age: Int? = null) {
    fun isOlderThen(other: Person): Boolean? {
        if (age == null || other.age == null) {
            return null
        }
        return age > other.age
    }
}

fun main() {
    println(Person("Sam", 35).isOlderThen(Person("Amy", 42))) // false
    println(Person("Sam", 35).isOlderThen(Person("Jane"))) // null
}

Person 클래스에 선언된 age 프로퍼티의 값은 java.lang.Integer로 저장된다. 하지만 그런 자세한 사항은 자바에서 가져온 클래스를 다룰 때만 문제가 된다. 코틀린에서 적절한 타입을 찾으려면 그 변수나 프로퍼티에 널이 들어갈 수 있는지만 고민하면 된다.

제네릭 클래스의 경우 래퍼 타입을 사용한다. 어떤 클래스의 타입 인자로 원시 타입을 넘기면 코틀린은 그 타입에 대한 박스 타입을 사용한다. 예를 들어 다음 문장에서는 null 값이나 널이 될 수 있는 타입을 전혀 사용하지 않았지만 만들어지는 리스트는 레퍼인 Integer 타입으로 이뤄진 리스트다.