kotlin 言語のアウトとイン、共分散と反分散

まず第一に、共分散と反変性は Kotlin に固有のものではなく、Java と C# にもそのような概念があります。

kotlin言語では  、out は共分散を意味し、in は反変を意味します。kotlin 言語で out と in を理解するために、まず Java ジェネリックスを例として使用します。ジェネリックスを使用する必要があるのは、ジェネリックスを使用する必要があるのは、その利点はコンパイルできることです。常にチェックされ、すべてのキャストは自動的かつ暗黙的に行われます。

1. Java の ? extends T および ? super T

? T を拡張します

継承関係を持つ複数のクラスを作成し、テストクラスを作成する

public class People{}
public class Man extends People{}
public class Test<T extends People>{
        public void run(List<T> aa){
        }
        public void run2(List<? extends T> aa){
        }
        public void run3(List<? super T> aa){
        }
}

run メソッドを呼び出してみる

   List<Man> list = new ArrayList<>();
   Test<People> test = new Test<>();
   test.run(list);

このときリストを渡すとコンパイルに失敗することが分かります ここで分析してみましょう: Test はジェネリッククラスです 使用する前は T は不確定です 使用した後は T が決まりますPeople; 実行するパラメータとしてリストを渡します。メソッドでは、List<People> aa= list と同等ですが、List<People> aa= list は true ではありません。Man は People から継承しますが、テストは People タイプのみを保存しますオブジェクト、リストは Man タイプのオブジェクトのみを保存します。テストはリストとは関係ありません。

run2 メソッドを呼び出してみる

   List<Man> list = new ArrayList<>();
   Test<People> test = new Test<>();
   test.run2(list);

この時点で、test.run2(list); 行のコードがコンパイルされて合格していることがわかりました。ここで分析しましょう: run2 メソッドにリストをパラメータとして渡すことは、List<? extends People> aa= list と同等であり、これは true です。List<? extends People> aa は、コレクションに People および People サブクラス オブジェクトが格納されることを意味します。前のセッションは制限されており、リストには People サブクラスのオブジェクトが格納されているため、コードがコンパイルされて確立されます。上限のワイルドカード <? extends T> が extends キーワードで宣言され、パラメータが T である可能性があることを示します。 T サブカテゴリ。

? スーパーT

次の方法で呼び出してみてください

 List<People> list2 = new ArrayList<>();
 Test<Man> test2 = new Test<>();
 test2.run(list2);
 test2.run2(list2);

 この時点で、run と run2 の両方でエラーが報告されていることがわかりました。その理由は、Test クラス オブジェクトをインスタンス化するときに、T が Man に置き換えられていたためです。test2 には People 型のデータのみが格納され、run メソッドと run2 メソッドのパラメーターには、のみが格納されます。 Man 型のデータなので、この 2 つは関係がないため、構文のコンパイルが間違っています。

次の呼び出しメソッドを試してください

   List<People> list2 = new ArrayList<>();
   Test<Man> test2 = new Test<>();
   test2.run3(list2);

この時点で、test2.run3(list); この行のコードがコンパイルされてパスしていることがわかりました。run3 メソッドのパラメータは List<? super T> aa です。? super T は下限のワイルドカードであり、使用時にパラメータの型が T または T の親クラスに制限されることを意味します。aa には型 T のオブジェクトが格納され、 T の親クラス; Test をインスタンス化するプロセスで、Man は T に置き換えられます。People はたまたま Man の親クラスです。Test の run3 メソッドを呼び出して最初のパラメータを渡す場合、List<? super Man と同等です。 > aa= list なので、コンパイルは成功します。

2. Kotlin のアウトとイン

kotlin の原理は上記の Java の原理と似ています。

 open class People
 class Man : People()
 class Test<T : People> {
        fun run(aa: MutableList<T>) {}
        fun run2(aa: MutableList<out T>) {}
        fun run3(aa: MutableList<in T>) {}
 }

呼び出し方法は以下の通りです。

 val list: MutableList<Man> = mutableListOf()
 val test: Test<People> = Test<People>()
 test.run2(list)

 val list2: MutableList<People> = mutableListOf()
 val test2: Test<Man> = Test<Man>()
 test2.run3(list2)

結論は:

kotlin の「out T」は、ワイルドカード型の前の項を制限する Java の「?extends T」に相当します。

kotlin の「in T」は Java の「?super T」に相当し、ワイルドカード型の次の項を制限します。

おすすめ

転載: blog.csdn.net/YDHIT/article/details/132599798