Kotlinのインとアウト は一般的なコンテンツです。Javaでは、extendsとsuperは比較としてカウントされます。
そして、Kotlinのinとoutと、javaのgenericextendsとsuperの違いは何ですか?
公式文書にはそのような段落があります:
次の簡単なことはできません(これは完全に安全です)。
// Java
void copyAll(Collection<Object> to, Collection<String> from) {
to.addAll(from);
// !!!对于这种简单声明的 addAll 将不能编译:
// Collection<String> 不是 Collection<Object> 的子类型
}
(Javaでは、このレッスンを難しい方法で学びました。「Effective Java」第3版、第28条を参照してください:リストは配列よりも優先されます)
Kotlinでのインとアウトの公式デザインはJavaジェネリックのレッスンに基づいていることがわかります
Kotlinの場合:
つまり、書き込みはできるが読み取りはできない、消費者であり、インバーターであるということです。
Outは読み取りのみが可能で、書き込みはできません。プロデューサーであり、共変です。
私が最初にこれを見たとき、これはどういう意味ですか?用途は何ですか?使い方?
次に、Javaのジェネリックスを見てみましょう
初見
リスト<?TextView> textViewsList = new ArrayList <>();を拡張します。
?extends TextViewは、textViewsList内の上限TextViewを決定しますが、それがTextView自体であるか、そのサブクラスのコレクションであるかは不明であるため、TextViewとそのサブクラスを追加すると、エラーが報告されます。つまり、禁止されている操作です。
しかし、TextView textView = textViewsList.get(0); //エラーなし
つまり、TextViewを使用して値を受け取るのは安全なので、値は間違いなくTextViewまたはそのサブクラスであるため安心できます。要約すると、値は取得できますが、値を割り当てることはできません。これは、次のことに対応します。outは読み取り可能ですが、書き込みはできません、プロデューサー、共分散
もう一度見てください
リスト<?スーパーTextView> textViewsList2 = new ArrayList <>();
?super TextView は、textViewsList2の下限がTextViewであると判断しますが、それがTextView自体であるか、その親クラスのコレクションであるかは不明です。どの親クラスがTextViewのコレクションであるかはわかりませんが、エラーは発生しません。 TextViewとそのサブクラスが追加されます。
しかし、値を取得するときObject object = textViewsList2.get(0);
TextViewの親クラスが不明であるため、値は最上位の親クラスObjectのみが受け取ることができます。
要約すると、値を割り当てることはできますが、値を取ることはできません。対応するものは次のとおりです。書き込みはできるが読み取りはできない、コンシューマー、インバーター
共変対応がありますか?extendsは、プロデューサーを読み取ることはできますが、変更することはできません
インバーター対応では?スーパーは変更のみ可能で、コンシューマーの読み取りはできません
これは、理解しやすいアナロジーにすぎません。インとアウトをまったく新しいものとして扱い、Javaとは何の関係もありません。
次に、書き込み専用と読み取り専用での使用方法を見てみましょう。
公式ドキュメントには次のように書かれています。クラスC
タイプパラメータT
が メンバーの出力位置でout
のみ発生する可能性がある場合に宣言されC
ますが、報酬は スーパークラスC<Base>
として安全C<Derived>
です。
interface MyOutClass<out T> {
fun methodDemo1(t: T)
// ↑
//此处报错 Type parameter T is declare as 'out'
// but occurs in 'in' position in type T
fun methodDemo2(): T
// ↑
// 放在返回值的位置就不会报错
}
つまり、ジェネリック型をなしで装飾すると、読み取り専用であるため、つまり安全に読み取ることができるため、戻り値の位置にのみ表示されます。パラメータの位置に置くと、outで変更されたジェネリック型をパラメータ値として使用できないというエラーが報告されます。読み取りはできますが、書き込みはできません
同じ:
interface MyInClass<in E> {
fun methodDemo1(e: E)
// ↑
// 此处不报错
fun methodDemo2(): E
// ↑
//此处报错 Type parameter E is declare as 'in'
// but occurs in 'out' position in type E
}
つまり、inを使用してジェネリック型を変更すると、書き込みのみが行われるため、パラメーター値の位置にのみ表示されます。戻り値の位置に置くと、inで変更されたジェネリック型を戻り値として使用できないというエラーが報告されます。つまり、書き込むことはできますが、読み取ることはできません。
ジェネリック型をパラメーターおよび戻り値として使用する場合は、inもoutも必要なく、変更しなくても問題ありません。
注1:パラメータとしてのみ使用できるか、戻り値がこのクラスの内部に相対的です。MyOutClassをパラメータとしてMyInClassのメソッドに入れることができます。MyOutClassジェネリックTはoutによって変更されますが、 MyOutClass専用です。クラスは内部で機能します。
interface MyInClass<in E> {
fun methodDemo1(e: E)
// ↑
// 此处不报错
fun methodDemo2(): E
// ↑
//此处报错 Type parameter E is declare as 'in'
// but occurs in 'out' position in type E
fun methodOut(outClass: MyOutClass<Any>)
// ↑
// MyOutClass 在 MyInClass的方法参数位置是没问题的
}
注2:注2:
class MyClass<P> {
// ↑
// 这个位置是可以声明in或out
// 可以在这里统一声明,就不必在每个对象声明处都进行声明
}
val myClass: MyClass<out TextView> = MyClass<TextView>()
// ↑ ↑
// 声明处可以设置是 赋值实现是不能用in或out修饰的
// in还是out
fun copy(from: Array<out Any>, to: Array<Any>) {
// ↑
// 方法参数位置是可以的
// 这样copy()不会做任何坏事,它无法写到from。
}
}
最初にCollection <String>をCollection <Object>に追加できないという問題については、Kotlinですでに可能です。
interface Source<out T> {
fun nextT(): T
}
fun demo(strs: Source<String>) {
val objects: Source<Any> = strs // 这个没问题,因为 T 是一个 out-参数
// ……
}
================================================== ==============================================
Outは出て、読むことはできますが書くことはできません。これはJavaのextendsに似ています。正確に読むことはできますが、書くことはできません。外から物を取り出すことができます。プロダクションのプロデューサーです。
「in」は、書き込むことはできるが読み取ることができないことを意味します。これはJavaのsuperに似ています。書き込むことはできますが、受信するにはObjectしか使用できません。消費者が消費するものに書き込む必要があります。物事。
文字通り覚えやすくなります。
共分散については、反変性です。覚えておいてください。幽霊はなぜこれと呼ばれるのか知っています。
Kotlinの公式中国語アドレス:ここをクリックしてください!