Red de conocimiento informático - Conocimiento del nombre de dominio - ¡Cómo entender bien los genéricos de Java!

¡Cómo entender bien los genéricos de Java!

La forma más sencilla de entender los genéricos de Java es pensar en ellos como una sintaxis conveniente que le ahorra algo de tiempo con las conversiones de tipos de Java:

1 List box = ... .

2 Apple = box.get(0);

El código anterior es muy claro: box es una Lista que contiene objetos Apple. Sin genéricos, el código anterior debería escribirse así:

1 List box = ... ;

2 Apple = (Apple) box.get(0);

p>

Obviamente, el principal beneficio de los genéricos es permitir que el compilador retenga información sobre los tipos de parámetros, realice operaciones de verificación de tipos y conversión de tipos: el compilador garantiza que estas conversiones de tipos estén absolutamente libres de errores.

Los compiladores pueden ayudar a los programadores a forzar una verificación exhaustiva de tipos y detectar errores en el momento de la compilación, en lugar de depender del programador para recordar los tipos de objetos y realizar conversiones de tipos (lo que puede causar errores cuando se ejecuta el programa). Fallos que son difíciles para depurar y reparar).

La composición de genéricos

La composición de genéricos introduce el concepto de variables de tipo. Según la especificación del lenguaje Java, una variable de tipo es un identificador no calificado que ocurre en:

Una declaración de clase genérica

Una declaración de interfaz genérica

Declaración de método genérico

Declaración de constructor genérico

Clases e interfaces genéricas

Si hay una o más variables de tipo en una clase o interfaz, entonces es genérica. Las variables de tipo se definen entre corchetes angulares y se colocan después del nombre de la clase o interfaz:

1 interfaz pública Lista extiende Colección {

2 ...

3 }

En resumen, las variables de tipo desempeñan el papel de parámetros, proporcionando información al compilador para la verificación de tipos.

Muchas clases de la biblioteca de clases de Java (como todo el marco de la Colección) se han modificado para generalizar tipos. Por ejemplo, la interfaz List que utilizamos en el primer fragmento de código anterior es una clase generalizada. En este código, box es un objeto List, que es una instancia de una implementación de clase de la interfaz List, con una variable de tipo Apple. Cuando se llama al método get, el compilador genera automáticamente el argumento de la variable usando ese tipo, devolviendo un objeto Apple.

De hecho, esta nueva etiqueta universal, o el método get en la interfaz Lista, tiene este aspecto:

1 T get(int index);

El p> El método

get en realidad devuelve un objeto de tipo T, que es la variable de tipo en la declaración List.

Métodos y constructores genéricos

Muy similares, los métodos y constructores también pueden ser genéricos si se declaran una o más variables de tipo en ellos.

1 public static T getFirst(List list)

Este método aceptará un parámetro de tipo List y devolverá un objeto de tipo T.

Ejemplo

Puede utilizar las clases genéricas proporcionadas en la biblioteca de clases de Java o puede utilizar sus propias clases genéricas.

Escritura de datos con escritura segura...

El siguiente código es un ejemplo en el que creamos una instancia de List y luego cargamos algunos datos:

1 Lista str = new ArrayList();

2 str.add("Hola ");

3 str.add("Mundo.") ;

Si intentamos cargar objetos de diferentes tipos en List, el compilador generará un error:

1 str add(1); / p>

Lectura de datos con seguridad de tipos...

Cuando procesamos un objeto List, siempre tenemos la garantía de obtener un objeto String:

1 String myString = str.get( 0);

Traversal

Muchas clases de la biblioteca (como Iterator) se han mejorado y generalizado. El método iterator() en la interfaz List ahora devuelve un Iterator, y el objeto T devuelto por su método next() ya no requiere conversión de tipo; puede obtener el tipo correcto directamente;

1 for (Iterator iter = str.iterator(); iter.hasNext();){

2 String s = iter.next();

3 System.out.print(s);

4 }

Uso de foreach

La sintaxis "para cada" también se beneficia de la generalización. El código anterior se puede escribir así:

1 for (String s: str) {

2 System.out.print(s);

3 }

Esto hace que sea más fácil de leer y mantener.

Autoboxing y Autounboxing

Cuando se utilizan genéricos de Java, el rasgo autoboxing/autounboxing se utilizará automáticamente, como el siguiente código:

1 List ints = new ArrayList();

2 ints.add(0);

3 ints.add(1);

4 ints. add( 1);

4

5 int suma = 0;

6 for (int i : ints) {

7 suma + = i;

8 }

Sin embargo, lo que debe comprender es que existen penalizaciones de rendimiento tanto para la encapsulación como para la no encapsulación, por lo que todas las generalizaciones deben usarse con precaución. .

Los genéricos son una nueva característica de Java SE 1.5. Los genéricos son esencialmente tipos parametrizados, lo que significa que el tipo de datos que se manipula se especifica como un parámetro. Este tipo parametrizado se puede utilizar para crear clases, interfaces y métodos, conocidos como clases genéricas, interfaces genéricas y métodos genéricos, respectivamente.

Los beneficios de introducir genéricos en el lenguaje Java son la seguridad y la simplicidad.

Antes de Java SE 1.5, en ausencia de genéricos, la "arbitrariedad" de los parámetros se lograba haciendo referencia al tipo de objeto. La desventaja de la "arbitrariedad" es que se debe realizar una conversión de tipo explícita, y esta conversión. requiere que los desarrolladores realicen una conversión de tipos en los parámetros reales. Cualquier " tiene la desventaja de tener que realizar una conversión explícita, lo que requiere que el desarrollador pueda predecir los tipos de parámetros reales.

En el caso de un error de conversión, es posible que el compilador no genere un error y la excepción solo aparecerá en tiempo de ejecución, lo que representa un riesgo de seguridad.

El beneficio de la generalización es que la seguridad de tipos se verifica en el momento de la compilación y todas las conversiones son automáticas e implícitas, lo que mejora la reutilización del código.

El uso de genéricos también tiene algunas reglas y restricciones:

1. Los parámetros de tipo de los genéricos solo pueden ser tipos de clase (incluidas las clases personalizadas), no tipos simples.

2. El mismo tipo genérico puede corresponder a múltiples versiones (porque el tipo de parámetro es incierto) y diferentes versiones de instancias de clases genéricas son incompatibles.

3. Un parámetro de tipo genérico puede tener múltiples parámetros de tipo.

4. Por ejemplo, los tipos de parámetros genéricos pueden utilizar la instrucción extends. Es costumbre convertirse en un "tipo acotado".

5. El tipo de parámetro de un tipo genérico también puede ser un tipo comodín. Por ejemplo, Class classType = Class.forName (java.lang.String);

Hay muchos contenidos como genéricos, interfaces, métodos, etc., que requieren cierto esfuerzo para comprenderlos y dominarlos. y aplicarlos hábilmente. Cuando intentaba comprender los genéricos, escribí dos ejemplos (escritos en base a las impresiones que vi. Para lograr la misma función, uno usó genéricos y el otro no. A través de la comparación, puede aprender rápidamente La aplicación de los genéricos). Si aprendes esto, básicamente aprenderás el 70% del contenido de los genéricos.

Ejemplo 1: uso de genéricos

public class Gen﹤T﹥ {

private T ob //definir variables miembro genéricas

public Gen(T ob) {

this.ob = ob;

}

public T getOb() {

return ob ;

}

public void setOb(T ob) {

this.ob = ob;

}

public void showTyep() {

Sistema: " + ob.getClass().getName());

}

}

clase pública GenDemo {

public static void main(String[] args ){

//definir una versión entera de la clase genérica Gen

Gen﹤Integer﹥ intOb=new Gen﹤Integer﹥(88);//p>

intOb.showTyep();

int i= intOb.getOb(); p>

System.out.println("valor= " + i);

System.out.println("---------------- - -----------------");

// Definir la versión de cadena de la clase general Gen

Gen﹤String﹥.

Gen﹤String﹥ strOb=new Gen﹤String﹥("¡Hola Gen!");

strOb.showTyep();

String s=strOb .getOb();

System.out.println(" value= " + s);

}

Ejemplo 2: no utilizar tipos genéricos

public class Gen2 {

private Object ob; //Definir un miembro de tipo genérico

public Gen2(Object ob) {

this. ob = ob;

}

Objeto público getOb() {

return ob;

}

public void setOb(Objeto ob) {

this.ob = ob;

}

public void showTyep() {

System.out.println("El tipo real de T es."):" + ob.getClass().getName());

}

}

clase pública GenDemo2 {

public static void main(String[] args) {

/Definir una versión entera de la clase Gen2

Gen2 intOb = new Gen2(new Integer(88));

intOb.showTyep();

int i = (Entero) intOb.getOb();

System.out.println("value=" + i);

System.out .println("------------- ---------------------");

// Defina la versión de cadena de la clase Gen2

Gen2 strOb = new Gen2("Hello Gen!");

strOb.showTyep();

String s = (Cadena) strOb.getOb();

System.out.println("value=" + s);

}

}

}

Resultados de la ejecución:

Los resultados de la ejecución de la demostración de los dos ejemplos son los mismos y la salida de la consola es la siguiente:

El tipo real de T El tipo real de T Sí:

java.lang.Integer

value= 88

---------- -------- ---------------

El tipo real de T es: java.lang.String

valor = ¡Hola general!

El proceso finalizó con el código de salida 0

De ahora en adelante, leer esto no debería ser un problema para las aplicaciones básicas de uso general y la lectura de códigos.

El proceso finalizó con el código de salida 0