Paradigma de Java Esas cosas (4)

Artículos anteriores relacionados con el paradigma de Java:

Paradigma de Java esas cosas (1)

Paradigma de Java esas cosas (2)

Paradigma de Java esas cosas (3)

1. Captura de comodines

En algunos casos, el compilador puede inferir el tipo de un comodín, por ejemplo, la lista puede ser definida como List <?>, Pero al evaluar expresiones, el compilador del código 推断出特定类型, 此场景称为通配符捕获.

Ver los dos métodos siguientes, test1 método en el que, después de un elemento i se extrae, a continuación, en, ya que el mecanismo de inferencia tipo compilador, i.get(0)se infiere a ser de tipo de objeto,
Inserte la descripción de la imagen aquí
la información dada es como sigue:
Inserte la descripción de la imagen aquí
para un tipo que contiene en su 通配符?de Variables, como la lista de parámetros de la función test1 aquí, el compilador pensará que hay algunos tipos T, de modo que para estas listas T es List <T>. No sabe qué tipo T representa, pero puede 为该类型创建一个占位符来指代 T 的类型. 占位符被称为这个特殊通配符的捕获(capture). En este caso, el compilador nombre “capture#1”asignado a una T.

En el mensaje de error se ?indica que es común , lo que indica que el parámetro tipo real Object y la captura del comodín (es decir, la captura de marcador de posición # 1) son ambos ?tipos y no se pueden distinguir, por lo que se informa el error de compilación.

⚠️ Nota: Cada comodín en cada declaración de variable obtendrá una captura diferente, por lo que en la declaración genérica foo (Par <?,?> X, Par <?,?> Y), el compilador dará a cada A la captura de los cuatro comodines se le asigna un nombre diferente porque no hay relación entre ningún parámetro de tipo desconocido.

Para algunas escenas generadas comodín capturados pueden ser capturados por una clase ayudante comodín interna ?, que es para ser capturado T, tales como:

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }


    // Helper method created so that the wildcard can be captured
    // through type inference.
    private <T> void fooHelper(List<T> list) {
        list.set(0, list.get(0));
    }

}

En este momento, en el método fooHelper, dado que la lista de parámetros se declara como un List<T>tipo, el list.get(0)valor de retorno ya no es del tipo Objeto, sino del Ttipo. Por supuesto, puede insertar el Tvalor de tipo determinado ( list.get(0)) en la lista ( List<T>tipo).
En realidad lo es 对原来未知的通配符类型命名,或称作对原来不相容的边界incompatible bounds进行相容处理.


Echemos un vistazo al método test2 nuevamente: el
Inserte la descripción de la imagen aquí
error es el siguiente:
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
Inserte la descripción de la imagen aquí
la <? extends java.lang.Number>suma de solicitud se captura aquí. <? super java.lang.Number>Los nombres de marcador de posición establecidos por el compilador son captura # 2 y captura # 3.
Tome el total ? extends java.lang.Numbercomo ejemplo, es decir, escriba argumentos (Integer y Float) y Los parámetros de tipo “capture#2”y los ? extends java.lang.Numbertipos capturados automáticamente por el compilador son todos tipos, pero es imposible determinar exactamente qué tipo (¿entero? ¿O flotante?), Por lo que el informe no puede encontrar un método adecuado.

Proporcione otro método de ayuda que intente hacer que list1.add () no informe un error: a
Inserte la descripción de la imagen aquí
partir del mensaje de error, se puede ver que no hay nadie que permita que el tipo Entero determine el ? extends java.lang.Numberobjeto capturado .

Resumen:
para las variables de tipo con comodines, el compilador inferirá automáticamente el tipo de tipos de comodines en combinación con los argumentos de tipo posteriores. Este escenario es la captura de comodines, pero los tipos capturados por el compilador a veces no pueden hacer que los resultados cumplan con las expectativas. Defina usted mismo un método auxiliar capture#XXXtransitivo y convierta el tipo de captura indefinido en un tipo determinado T, de modo que se cumpla el efecto esperado; pero no todos los comodines que informan errores después de la captura pueden resolverse mediante el método de tránsito auxiliar, porque la lógica del código original No esta bien.

2. Borrar el paradigma

Los genéricos se introdujeron en el lenguaje Java para proporcionar una verificación de tipos más estricta en el momento de la compilación y admitir la programación universal. Para implementar los genéricos, el compilador de Java aplica el borrado de tipos a:

  • Si los parámetros de tipo no están delimitados, todos los parámetros de tipo del tipo genérico se reemplazan con sus límites u Objeto, por lo que el código de bytes generado solo contiene clases, interfaces y métodos ordinarios.
  • Si es necesario, inserte conversiones de tipo para mantener la seguridad de tipo.
  • Los métodos de puente se generan para preservar el polimorfismo en tipos genéricos extendidos.

El borrado de tipos garantiza que no se creen nuevas clases para los tipos parametrizados, por lo que los genéricos no generan gastos generales de tiempo de ejecución.

En el proceso de borrado de tipo, el compilador de Java borrará todos los parámetros de tipo y reemplazará cada uno de ellos con el primer límite cuando los parámetros de tipo estén delimitados. Si el parámetro de tipo no tiene límites, se reemplaza con Object.

那为什么Java编译器要进行类型擦除呢?只是为了不为参数化类型创建新类来不产生运行时开销吗?

Origen : Java no tenía genéricos al principio, y luego 1.5 añadieron genéricos 为了能向前兼容(旧版本的jvm能解释运行新版本的.class文件)所以就采用了伪泛型——“泛型擦除”, y se ha conservado.

Principio : La información genérica solo existe en la etapa de compilación del código. Después de la 进入 JVM 之前,与泛型相关的信息会被擦除掉eliminación, se convertirá en el tipo original (eliminar <T>, borrar la T en el método en Object). Por ejemplo, Generic <T> se borrará en Generic. También se debe tener en cuenta que los diferentes comodines se borran de diferentes maneras:

Mantra: [Guardar en: Bajar el límite; Sacar: Tomar el límite superior] —o— [Guardar en, tomar]

  • Cuando el tipo genérico se usa como parámetro entrante del método, se reemplaza por el límite inferior del tipo salvaje en este momento, como el método add

  • Cuando se utiliza el genérico como parámetro de retorno del método, esta vez se reemplaza con el límite superior del comodín genérico, como el método get

List<? extends Integer> list1 = new ArrayList<Integer>();
list1.add(null); // 此时传入取<? extends Integer> 下界————无 所以只能传null,否则报错
Integer integer1 =  list1.get(0); // // 此时返回取<? extends Integer> 上界————Integer

List<? super Integer> list2 = new ArrayList<Integer>();
list2.add(111); // 此时传入取<? super Integer> 下界——————Integer
Integer integer2 =  (Integer) list2.get(0); // // 此时返回取<? super Integer> 上界————Object

Referencia:
artículo del sitio web oficial sobre la captura de comodines: una traducción al chino correspondiente a los métodos de captura y ayuda comodín
: tutorial de Java ™ (captura genérica comodín y método de ayuda)
Introducción del sitio web oficial a la eliminación de tipos: una traducción al chino correspondiente a borrado de tipos
: Java ™ Tutorial (Borrar tipo)

Teoría y práctica de Java: uso de comodines para simplificar genéricos, uso de
diferencias genéricas de Java y borrado genérico Tutorial detallado de
Java ™ (limitaciones de genéricos)

82 artículos originales publicados · Me gusta 86 · Visita 110,000+

Supongo que te gusta

Origin blog.csdn.net/unicorn97/article/details/102053961
Recomendado
Clasificación