Kotlin listOf の実態はなに
Kotlin における listOf
は、以下のように
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html
fun <T> listOf(vararg elements: T): List<T>
で List
(interface) が返ってきます。
利用する分には全く問題がないめちゃくちゃ便利なビルダーですが、ふとしたことをきっかけに Kotlin における listOf()
が具体的な型として何を返してるのかなどの仕組みが気になってしまったので軽く調べてみました。
(当初は普通に java.util.ArrayList
が返ってくると思ってた。)
環境としては、以下で調べてみたりしてます - Kotlin 1.5.30 (そんなに他のバージョンも違わないはず) - IntelliJ IDEA
listOf -> CollectionsKt.listOf
まずは、おなじみ Kotlin の Plugin で Bytecode に変換したのち Decompile して Java のコードとして見てみます。
( Tools
> Kotlin
> Show Kotlin Bytecode
でみることができます)
val list = listOf<String>("a", "b")
↓
List list = CollectionsKt.listOf(new String[]{"a", "b"});
CollectionsKt#listOf
は
https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/src/kotlin/collections/Collections.kt#L77
にありました
public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()
どうやら vararg
に対して asList()
を呼び出しているようです。
vararg に対しての asList() -> ArraysKt.asList
こちらも Kotlin の Plugin で Bytecode に変換して Java Decompile してみます。
val list = elements.asList()
↓
List list = ArraysKt.asList(elements);
ArraysKt#asList
は IntelliJ から遷移すると以下の実装となっていた。
public actual fun <T> Array<out T>.asList(): List<T> {
return ArraysUtilJVM.asList(this)
}
(補足)
//
// NOTE: THIS FILE IS AUTO-GENERATED by the GenerateStandardLib.kt
// See: https://github.com/JetBrains/kotlin/tree/master/libraries/stdlib
//
とあるのでおそらくソースコード自体にはなく? Jetbrains/kotlin では見つからなかった。
ArraysKt.asList -> java.util.Arrays$ArrayList の生成
ArraysUtilJVM.asList(this)
の部分は、
https://github.com/JetBrains/kotlin/blob/master/libraries/stdlib/jvm/src/kotlin/collections/ArraysUtilJVM.java
にありました
class ArraysUtilJVM {
static <T> List<T> asList(T[] array) {
return Arrays.asList(array);
}
}
Java の return Arrays.asList(array); を呼び出してたのでそれをたどっていくと今自分が開いてる IntelliJ で見ると以下の実装に遷移する
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
return new ArrayList<>(a);
にもあるように ArrayList
を返却している。
しかしこの ArrayList
は、型の宣言としては java.util.Arrays$ArrayList
となるので
https://docs.oracle.com/javase/jp/8/docs/api/java/util/ArrayList.html
で宣言されているような java.util.ArrayList
ではなく Arrays
のインナークラスとして宣言されたものが利用されているので、 以下のような判定などはできず、 List
インターフェースとして利用するという形になります (それはそう)
val list = listOf("a", "b", "c")
list is java.util.ArrayList // これは false となる
まとめ
- Kotlin の
listOf
は、 Java のjava.util.Arrays.asList
と同一であった listOf
は、java.util.Arrays$ArrayList
を返していて、java.util.ArrayList
とは型が異なる