Comparación de la salida covariante y contravariante genérica de Kotlin y la extensión y super en Java

En  Kotlin, la entrada y la salida son contenido genérico. En Java, las extensiones y super se cuentan como comparaciones.

 ¿Y cuál es la diferencia entre in y out en Kotlin y extensiones genéricas y super en java?

Hay tal párrafo en el documento oficial:

No podemos hacer las siguientes cosas simples (esto es completamente seguro):

// Java
void copyAll(Collection<Object> to, Collection<String> from) {
  to.addAll(from);
  // !!!对于这种简单声明的 addAll 将不能编译:
  // Collection<String> 不是 Collection<Object> 的子类型
}

(En Java, aprendimos esta lección de la manera difícil, consulte "Java efectivo" Tercera edición , Artículo 28: Las listas tienen prioridad sobre las matrices )

Se puede ver que el diseño oficial de in y out en Kotlin se basa en las lecciones de java genéricos

En Kotlin:

en significa que se puede escribir pero no leer, es un consumidor y es un inversor;

Out solo se puede leer pero no escribir, es productor, covariante;

¿Qué significa esto cuando lo vi por primera vez? ¿Cuál es el uso? ¿cómo utilizar?

 

A continuación, echemos un vistazo a los genéricos en Java.

Primera vista

Lista <? extiende TextView> textViewsList = new ArrayList <> ();

? extiende TextView determina el límite superior TextView en textViewsList, pero no está claro si es el TextView en sí mismo o la colección de sus subclases, por lo que agregar TextView y sus subclases informará un error, es decir, es una operación prohibida.

Pero TextView textView = textViewsList.get (0); // Sin error

Es decir, es seguro usar TextView para recibir el valor, por lo que puede estar seguro de que el valor es definitivamente TextView o su subclase. El resumen es que se pueden tomar valores, pero no se pueden asignar valores, correspondientes a: out se puede leer pero no escribir, productor, covarianza 

Mirar de nuevo

Lista <? super TextView> textViewsList2 = new ArrayList <> ();

 ? super TextView  determina que el límite inferior de textViewsList2 es TextView, pero no se sabe si es el TextView en sí mismo o la colección de su clase principal. Aunque no está seguro qué clase principal es la colección de TextView, no hay error cuando Se agregan TextView y sus subclases.

Pero al obtener el valor Object object = textViewsList2.get (0);

Debido a que no está claro qué clase principal de TextView es, el valor solo puede ser recibido por la clase principal de nivel superior Object.

El resumen es que puede asignar valores pero no tomar valores. Lo correspondiente es: en se puede escribir pero no leer, consumidor, inversor

 

¿Correspondencia covariante? Las extensiones solo pueden leer pero no modificar el productor

en la correspondencia del inversor? super solo puede modificar pero no leer al consumidor

Esta es solo una analogía que es más fácil de entender: es completamente posible tratar la entrada y la salida como cosas nuevas y no tener nada que ver con Java.

 

A continuación, echemos un vistazo a cómo usar solo escritura y solo lectura

La documentación oficial lo dice: cuando  se declara un C parámetro de tipo de clase  cuando solo puede ocurrir en  la posición de salida de los miembros, pero las recompensas son  seguras como la  superclase.ToutCC<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
        //             ↑
        // 放在返回值的位置就不会报错 
}

Es decir, cuando decoras un tipo genérico sin, solo puede aparecer en la posición del valor de retorno, porque es de solo lectura, es decir, es seguro de leer. Si lo coloca en la posición de parámetro, se informará un error, diciendo que el tipo genérico modificado por out no se puede usar como valor de parámetro. Solo puede leer pero no escribir

mismo:

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
}

Es decir, cuando modificas un tipo genérico con in, solo puede aparecer en la posición del valor del parámetro, porque solo escribe. Si lo coloca en la posición de valor de retorno, se informará un error, diciendo que el tipo genérico modificado por in no se puede utilizar como valor de retorno. Es decir, se puede escribir pero no se puede leer.

Si desea que se use un tipo genérico como parámetro y como valor de retorno, entonces no se necesita ni in ni out, y está bien sin modificaciones.

Nota 1: Solo se puede usar como parámetro o el valor de retorno es relativo al interno de esta clase. Es posible poner MyOutClass en un método de MyInClass como parámetro. Aunque el MyOutClass genérico T es modificado por out, es es solo para MyOutClass. La clase funciona internamente.

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的方法参数位置是没问题的
}

Nota 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。
    }    
}

Para el problema de que Collection <String> no se puede agregar a Collection <Object> al principio, ya es posible en Kotlin:

interface Source<out T> {
    fun nextT(): T
}

fun demo(strs: Source<String>) {
    val objects: Source<Any> = strs // 这个没问题,因为 T 是一个 out-参数
    // ……
}

================================================ ============================================

 

Out sale, se puede leer pero no se puede escribir. Es análogo a extensions en java. Se puede leer con precisión pero no se puede escribir. Puede sacar cosas de fuera. Es el productor de la producción.

"en" significa que se puede escribir, pero no se puede leer. Es análogo a super en Java. Puedes escribir, pero solo puedes usar Object para recibir. Tienes que escribir cosas en las que hay un consumidor que consume cosas.

Será más fácil memorizarlo literalmente.

En cuanto a nuestra covarianza; en contravarianza. Solo recuérdalo. El fantasma sabe por qué se llama así.

 

Dirección oficial china de Kotlin: ¡haga clic aquí!

 

 

 

Supongo que te gusta

Origin blog.csdn.net/u011288271/article/details/107318507
Recomendado
Clasificación