Java Genéricos

Java Genéricos (generics) es una nueva característica introducida en JDK 5. Los genéricos proporcionan un mecanismo de detección de seguridad de tipos en tiempo de compilación, que permite a los programadores detectar tipos ilegales en tiempo de compilación.

La esencia de los genéricos es el tipo parametrizado, es decir, el tipo de datos que se opera se especifica como un parámetro.

Supongamos que tenemos un requisito: escribir un método de ordenación que pueda ordenar matrices de enteros, matrices de cadenas e incluso matrices de cualquier otro tipo. ¿Cómo implementarlo?

La respuesta es que se puede usarJava Genéricos。

Usando el concepto de Java Genéricos, podemos escribir un método genérico para ordenar una matriz de objetos. Luego, llamamos a ese método genérico para ordenar matrices de enteros, matrices de flotantes, matrices de cadenas, etc.


Métodos genéricos

Puedes escribir un método genérico que, al ser invocado, pueda recibir parámetros de diferentes tipos. Según el tipo de parámetro pasado al método genérico, el compilador maneja adecuadamente cada llamada al método.

Las siguientes son las reglas para definir métodos genéricos:

  • Todas las declaraciones de métodos genéricos tienen una parte de declaración de parámetros de tipo (delimitada por corchetes angulares), que precede al tipo de retorno del método (en el siguiente ejemplo,<E>)。
  • Cada sección de declaración de parámetros de tipo contiene uno o más parámetros de tipo, separados por comas. Un parámetro genérico, también llamado variable de tipo, es un identificador que se utiliza para especificar un nombre de tipo genérico.
  • Los parámetros de tipo se pueden usar para declarar el tipo de retorno y pueden servir como marcadores de posición para los tipos de argumentos reales que recibe el método genérico.
  • La declaración del cuerpo del método genérico es igual que la de otros métodos. Ten en cuenta que los parámetros de tipo solo pueden representar tipos de referencia, no tipos primitivos (comoint、double、charetc.).

Marcadores de genéricos en Java:

  • E- Element (se usa en colecciones, porque las colecciones almacenan elementos)
  • T- Type (clase Java)
  • K- Key (clave)
  • V- Value (valor)
  • N- Number (tipo numérico)
  • ?- Representa un tipo Java indeterminado.

Ejemplo

El siguiente ejemplo demuestra cómo usar un método genérico para imprimir elementos de matrices de diferentes tipos:

Ejemplo

public class GenericMethodTest { //Método genérico printArray public static < E > void printArray( E[] inputArray ) { //Imprime los elementos de la matriz for ( E element : inputArray ){ System.out.printf( "%s ", element ); } System.out.println(); } public static void main( String args[] ) { //Crea matrices de diferentes tipos: Integer, Double y Character Integer[] intArray = { 1, 2, 3, 4, 5 }; Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 }; Character[] charArray = { 'H', 'E', 'L', 'L', 'O' }; System.out.println( "Los elementos de la matriz de enteros son:" ); printArray( intArray ); //Pasa una matriz de enteros System.out.println( "\nLos elementos de la matriz de dobles son:" ); printArray( doubleArray ); //Pasa una matriz de dobles System.out.println( "\nLos elementos de la matriz de caracteres son:" ); printArray( charArray ); //Pasa una matriz de caracteres } }

Compila el código anterior y el resultado de la ejecución es el siguiente:

整型数组元素为:
1 2 3 4 5 

双精度型数组元素为:
1.1 2.2 3.3 4.4 

字符型数组元素为:
H E L L O 

Parámetros de tipo acotados:

Quizás a veces quieras limitar el rango de tipos que se permiten pasar a un parámetro de tipo. Por ejemplo, un método que opera con números puede querer aceptar solo instancias de Number o subclases de Number. Ese es el propósito de los parámetros de tipo acotados.

Para declarar un parámetro de tipo acotado, primero escribe el nombre del parámetro de tipo, seguido de la palabra clave extends y, finalmente, su límite superior.

Ejemplo

El siguiente ejemplo demuestra cómo se usa "extends" en el sentido general de "extends" (clases) o "implements" (interfaces). El método genérico de este ejemplo devuelve el máximo de tres objetos comparables.

Ejemplo

public class MaximumTest { //Compara tres valores y devuelve el máximo public static <T extends Comparable<T>> T maximum(T x, T y, T z) { T max = x; //Supongamos que x es el valor máximo inicial if ( y.compareTo( max ) > 0 ){ max = y; //y es mayor } if ( z.compareTo( max ) > 0 ){ max = z; //ahora z es mayor } return max; //Devuelve el objeto máximo } public static void main( String args[] ) { System.out.printf( "El mayor de %d, %d y %d es %d\n\n", 3, 4, 5, maximum( 3, 4, 5 ) ); System.out.printf( "El mayor de %.1f, %.1f y %.1f es %.1f\n\n", 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) ); System.out.printf( "El mayor de %s, %s y %s es %s\n","pear", "apple", "orange", maximum( "pear", "apple", "orange" ) ); } }

Compila el código anterior y el resultado de la ejecución es el siguiente:

3, 4 和 5 中最大的数为 5

6.6, 8.8 和 7.7 中最大的数为 8.8

pear, apple 和 orange 中最大的数为 pear

Clases genéricas

La declaración de una clase genérica es similar a la de una clase no genérica, excepto que se agrega una sección de declaración de parámetros de tipo después del nombre de la clase.

Igual que en los métodos genéricos, la sección de declaración de parámetros de tipo de una clase genérica contiene uno o más parámetros de tipo separados por comas. Un parámetro genérico, también llamado variable de tipo, es un identificador que se utiliza para especificar un nombre de tipo genérico. Debido a que aceptan uno o más parámetros, estas clases se denominan clases parametrizadas o tipos parametrizados.

Ejemplo

El siguiente ejemplo demuestra cómo definimos una clase genérica:

Ejemplo

public class Box<T> { private T t; public void add(T t) { this.t = t; } public T get() { return t; } public static void main(String[] args) { Box<Integer> integerBox = new Box<Integer>(); Box<String> stringBox = new Box<String>(); integerBox.add(new Integer(10)); stringBox.add(new String("Tutorial para novatos")); System.out.printf("El valor entero es: %d\n\n", integerBox.get()); System.out.printf("La cadena es: %s\n", stringBox.get()); } }

Compila el código anterior y el resultado de la ejecución es el siguiente:

整型值为 :10

字符串为 :Ejemplo

Comodines de tipo

1. Los comodines de tipo generalmente se usan?en lugar de parámetros de tipo concretos. Por ejemploList<?>lógicamente esList<String>,List<Integer>y todos losList<tipo de argumento concreto>la clase padre de.

Ejemplo

import java.util.*; public class GenericTest { public static void main(String[] args) { List<String> name = new ArrayList<String>(); List<Integer> age = new ArrayList<Integer>(); List<Number> number = new ArrayList<Number>(); name.add("icon"); age.add(18); number.add(314); getData(name); getData(age); getData(number); } public static void getData(List<?> data) { System.out.println("data :" + data.get(0)); } }

El resultado de salida es:

data :icon
data :18
data :314

Análisis:PorquegetData()el parámetro del método esList<?>del tipo, por lo tantoname,age,numbertodos pueden usarse como argumentos reales de este método; esa es la función de los comodines.

2. El límite superior de los comodines de tipo se define mediante formas como Listpara definirlo; de este modo, el comodín genérico acepta Number y sus tipos de subclase inferiores.

Ejemplo

import java.util.*; public class GenericTest { public static void main(String[] args) { List<String> name = new ArrayList<String>(); List<Integer> age = new ArrayList<Integer>(); List<Number> number = new ArrayList<Number>(); name.add("icon"); age.add(18); number.add(314); //getUperNumber(name);//1 getUperNumber(age);//2 getUperNumber(number);//3 } public static void getData(List<?> data) { System.out.println("data :" + data.get(0)); } public static void getUperNumber(List<? extends Number> data) { System.out.println("data :" + data.get(0)); } }

Resultado de salida:

data :18
data :314

Análisis:En//1se producirá un error en ..., porquegetUperNumber()el parámetro en el método ya ha limitado el límite superior del parámetro genérico aNumber, por lo que el tipo genérico esStringno está dentro de este rango, por lo que se reportará un error.

3. El límite inferior de los comodines de tipo se define mediante formas comoList<? super Number>para definirlo, lo que significa que el tipo solo puede aceptarNumbery sus superclases, comoObjectinstancias del tipo.

Otras extensiones