2017-08-20 8 views
5

私はリフレクションで遊んでいます。この問題が出てきました。 ::class構文を介して結合クラス参照を使用している場合、私は共変KClassの種類を取得:バインドされたクラス参照が共変型を返すようにする目的は何ですか?

fun <T> foo(entry: T) { 
    with(entry::class) { 
     this // is instance of KClass<out T> 
    } 
} 

私は、ドキュメントから学ぶことができるように、これはオブジェクトの正確な型を返します、ケースには、サブタイプのインスタンスでありますTであり、したがって分散変更子である。これは(私が何をしようとしているとする)Tクラスで宣言されたプロパティを取得し、その値を取得防止

fun <T> foo(entry: T) { 
    with(entry::class) { 
     for (prop in memberProperties) { 
      val v = prop.get(entry) //compile error: I can't consume T 
     } 
    } 
} 

は、しかし、私は解決策を取得するには、オブジェクト参照にjavaClass.kotlin拡張機能を使用していることがわかりました代わりに、不変型:

fun <T> foo(entry: T) { 
    with(entry.javaClass.kotlin) { 
     this // is instance of KClass<T> 
    } 
} 

このようにして、実行時に正確な型と型を消費する可能性の両方が得られます。私はそれが正しい得た場合::classがあり、

class Derived: Base() 

fun foo(entry: Base) { 
    with(entry.javaClass.kotlin) { 
     println(this == Derived::class) 
    } 
} 

fun main(args: Array<String>) { 
    val derived = Derived() 
    foo(derived) // prints 'true' 
} 

:私は後者の方法で、一般的なのではなく、スーパータイプを使用する場合

興味深いことに、私はまだ分散を必要とせずに、正しい型へのアクセスを取得しますワイルドカードを含むバリアント型を返すjava getClassを呼び出し、javaClassgetClassで、特定の型へのキャストを呼び出します。 しかし、実行時に厳密なクラスにアクセスして自由に使用できる他の方法があるとすれば、型を生成することだけを制限するときに共存するKClassが必要なのはなぜですか?より即座に::classは、設計上不変型を返すべきです。

答えて

3

バインドされた::class参照の共分散の理由は、式が評価されるオブジェクトの実際の実行時の型が、式の宣言型または推論型と異なる場合があります。

例:

open class Base 
class Derived : Base() 

fun someBase(): Base = Derived() 

val kClass = someBase()::class 

表現someBase()Baseとして入力されていますが、実行時に、それは、それが評価されますことをDerivedオブジェクトです。

someBase()::classを不変式KClass<Base>とタイプすると、実際にはこの式を評価した結果はKClass<Derived>です。これを可能に矛盾を解決するために

(つまり、壊れ型の安全性につながる)、バインドされているすべてのクラス参照が共変です:someBase()::classは、実行時someBase()Baseのサブタイプであるかもしれないので、これはクラスであるかもしれないことを意味し、KClass<out Base>ですトークンのサブタイプはBaseです。

これは、当然のことながら、結合していないクラス参照の場合ではありません:あなたはBase::classを取るとき、あなたはそれがそのサブタイプのいくつかのBaseとないのクラストークンなので、それはKClass<Base>不変だということを確実に知ります。

+0

私はあなたの言うことを理解しています。しかし、私のポイントは、もし私がsomeBase()。javaClassを使うならば。kotlin、私はまだ実行時に正しいサブタイプ(派生)を持っていますが、それらの拡張関数はジェネリックを使用するので、コンパイル時にも分散はありません。 :: class構​​文は、javaClass.kotlinのように機能するように改良されています。javaClass.kotlinは、イディオム的にはあまり即座ではありません。彼らは同じことをして、kotlinクラスを返すように思えますが、後者はもっと冗長でありながらより良い仕事をしてくれます。 – devrocca

+0

これは逆です: '.javaClass'は以前に導入されました。誤った設計とみなされた。 '.javaClass'は廃止されました([1.1 RCで)](https://blog.jetbrains.com/kotlin/2017/02/kotlin-1-1-release-candidate-is-here/) 1.1最終リリースでは、廃止予定が削除されました。 – hotkey

+0

面白いことです。しかし、リフレクションによって取得されたプロパティを呼び出す必要がある場合は、受信者が必要です。共変タイプではバインドされたプロパティを使用できません。 '.javaClass'は利用できませんでした。 – devrocca

関連する問題