クラス ≠ 型
KClassは、クラス定義そのものの情報。
KTypeは、変数の型情報。
「クラス」は「型」の情報の一部。「クラス」=「型」ではない。
たとえば、変数の型はNullable
で宣言できる。
class Something(
val str: String?
)
Nullabilityは変数の型としての情報であって、クラス自体の定義にはふくまれない。
このように「型」は「クラス」が含まない情報を持つことがあるので、
Kotlinはこれらを区別し、それぞれKTypeとKClassというクラスを与えている。
実用面
リフレクションでクラスのフィールドの型情報を取得するようなケースだと、KTypeで扱ったほうが都合がよさそうだ。
たとえば、クラスにジェネリクス変数(type parameter)を持ったフィールド、典型的にはList型
があるとする。
class Something2(
val list: List<String>
)
リフレクションでフィールドの型情報を収集したいとき、KClassからは型のジェネリクス変数のクラス情報(List<String>でいうString
)までは取得できない1。
KClassは単なるクラス定義で、クラス定義上ではジェネリクス変数は具体的な型情報を持たないからだ。
この点KTypeはジェネリクス変数のクラス情報まで取得できる2。ありがたい。
このほか、Nullablility
だとかの型としての情報が欲しければ、KType
。
クラスのコンストラクタ情報が欲しいだとかは、KClass
をつかう。ちがいが分かれば、使い分けはそこまで難しくない。
むすびと参考
リフレクションでフィールドのList<String>でいうString相当の情報がとれず時間を使ったので、屍として置いておきます。
JavaにはKTypeに相当するものがあった記憶がありません。あったのかな…
参考サイト
https://discuss.kotlinlang.org/t/why-is-kclass-not-a-ktype/3341
-
KClass#typeParametersというそれっぽいAPIはありますが、こいつは型パラメータそのもの("out T"とか)を返す模様です ↩
-
型のクラスが持つジェネリクス変数のクラス情報はKType#argumentsでとれます。「型のクラスが持つジェネリクス変数のクラス情報」
↩