Los llamados genéricos: le permiten especificar parámetros de tipo al definir clases e interfaces. Este parámetro de tipo se determinará al declarar variables y crear objetos (es decir, pasar parámetros de tipo reales, que también se pueden llamar argumentos de tipo).
Clase o interfaz genérica
El código de copia de sintaxis "diamante" es el siguiente:
//definición
La lista de interfaz pública <E> extiende la colección <E>
la clase pública HashMap<K,V> extiende AbstractMap<K,V> implementa Map<K,V>, clonable, serializable
//usar
Lista<Cadena> lista = nueva ArrayList();
// Después de Java 7, puede omitir el parámetro de tipo de los corchetes angulares detrás de él.
Lista<Cadena> lista = nueva ArrayList<>();
Derivar una subclase de una clase genérica
Copie el código de código de la siguiente manera:
//Método 1
La aplicación de clase pública extiende GenericType<String>
//Método 2
La clase pública App<T> extiende GenericType<T>
//Método 3
La aplicación de clase pública extiende GenericType
Pseudo genéricos
No existe una clase genérica real. Las clases genéricas son transparentes para la máquina virtual Java. La JVM no conoce la existencia de clases genéricas. En otras palabras, la JVM procesa las clases genéricas de la misma manera que las clases ordinarias. en métodos estáticos, bloques de inicialización estáticos y variables estáticas.
- Los siguientes métodos son todos incorrectos. El código de copia es el siguiente:
datos T estáticos privados;
estático{
Tf;
}
función de vacío estático público(){
T nombre = 1;
}
El siguiente ejemplo puede verificar desde el lado que no existe una clase genérica. Copie el código.
principal vacío estático público (String [] argumentos) {
Lista<Cadena> a1 = nueva ArrayList<>();
Lista<Integer> a2 = nueva ArrayList<>();
System.out.println(a1.getClass() == a2.getClass());
System.out.println(a1.getClass());
System.out.println(a2.getClass());
}
El código de copia de salida es el siguiente:
verdadero
clase java.util.ArrayList
clase java.util.ArrayList
Escriba comodín
En primer lugar, debe quedar claro que si Foo es la clase principal de Bar, pero List<Foo> no es la clase principal de List<Bar>, Java usa "?" para representar varias clases principales genéricas. comodines genéricos, es decir, Lista <?> representa la clase principal de varias Listas genéricas. Con este tipo de comodín, los genéricos de Lista no pueden establecer (establecer) elementos, solo pueden obtener (obtener) elementos. Como el programa no puede determinar los tipos en la Lista, no puede agregar objetos. Pero el objeto obtenido debe ser de tipo Objeto.
Los siguientes métodos se compilarán con errores:
Copie el código de código de la siguiente manera:
Lista<?> lista = nueva ArrayList<>();
lista.add(nuevo objeto());
Algunas ideas:
1. Los objetos List<String> no se pueden utilizar como objetos List<Object>, es decir: la clase List<String> no es una subclase de la clase List<Object>.
2. Las matrices son diferentes de los genéricos: suponiendo que Foo es un subtipo (subclase o subinterfaz) de Bar, entonces Foo[] sigue siendo un subtipo de Bar[] pero G<Foo> no es el subtipo G<Bar>;
3. Para representar la clase principal de varias Listas genéricas, necesitamos usar comodines de tipo. El comodín de tipo es un signo de interrogación (?). Pase un signo de interrogación como argumento de tipo a la colección de Listas, escrito: Lista<? > (es decir, lista desconocida de elementos de tipo). Este signo de interrogación (?) se denomina carácter comodín y su tipo de elemento puede coincidir con cualquier tipo.
Límite superior comodín
List<? extends SuperType> representa la clase principal o ella misma de todas las listas genéricas de SuperType. Los genéricos con límites superiores comodín no pueden tener métodos establecidos, solo métodos de obtención.
Establecer el límite superior de comodines puede resolver los siguientes problemas: Dog es una subclase de Animal y existe un método getSize para obtener el número de listas entrantes. Copie el código de la siguiente manera:
clase abstracta Animal {
ejecución pública abstracta vacía();
}
clase Perro extiende Animal {
ejecución pública vacía () {
System.out.println("corredor para perros");
}
}
Aplicación de clase pública {
getSize vacío estático público (lista <Animal> lista) {
System.out.println(lista.tamaño());
}
público estático vacío principal (String [] argumentos) {
Lista<Perro> lista = nueva ArrayList<>();
getSize(lista); // Error de compilación aquí
}
}
El motivo del error de programación aquí es que List<Animal> no es la clase principal de List<Dog>. La primera solución es cambiar el parámetro formal Lista <Animal> en el método getSize a Lista <?>, pero en este caso, se requiere una conversión de tipo forzada cada vez que se obtiene el objeto, lo cual es más problemático. El uso del límite superior comodín resuelve muy bien este problema. Puede cambiar Lista <Animal> a Lista <? extiende Animal>, y no habrá errores en la compilación y no se requiere conversión de tipo.
Límite inferior para comodines
List<? super SubType> representa el límite inferior de la lista genérica de subtipo. Los genéricos con límites superiores comodín no pueden tener métodos get, solo métodos set.
Métodos genéricos
Si define clases e interfaces sin utilizar parámetros de tipo, pero desea definir parámetros de tipo usted mismo al definir métodos, esto también es posible. La firma del método de un método genérico tiene más declaraciones de parámetros de tipo que la firma del método de un método ordinario. Las declaraciones de parámetros de tipo están entre corchetes angulares. Varios parámetros de tipo están separados por comas (,). Modificadores y tipos de valores de retorno de métodos. El formato de sintaxis es el siguiente:
Copie el código de código de la siguiente manera:
Nombre del método del tipo de valor de retorno del modificador (lista de tipos) {
//cuerpo del método
}
Los métodos genéricos permiten que los parámetros de tipo se utilicen para expresar dependencias de tipo entre uno o más parámetros de un método, o entre los valores de retorno del método y los parámetros. Si no existe tal dependencia de tipos, no se deben utilizar métodos genéricos. El método de copia de Colecciones utiliza métodos genéricos:
Copie el código de código de la siguiente manera:
copia nula estática pública <T> (Lista<? super T> destino, Lista<? extiende T> src){...}
Este método requiere que el tipo src sea una subclase del tipo dest o él mismo.
Borrar y convertir
En código genérico estricto, las clases con declaraciones genéricas siempre deben tener parámetros de tipo. Sin embargo, para ser coherente con el código Java antiguo, también se permite utilizar clases con declaraciones genéricas sin especificar parámetros de tipo. Si no se especifica ningún parámetro de tipo para esta clase genérica, el parámetro de tipo se denomina tipo sin formato y por defecto es el primer tipo de límite superior especificado cuando se declaró el parámetro.
Cuando un objeto con información genérica se asigna a otra variable sin información genérica, toda la información de tipo entre corchetes angulares se desecha. Por ejemplo, si un tipo List <String> se convierte en List, la verificación de tipo de los elementos de la colección de List se convierte en el límite superior de la variable de tipo (es decir, Objeto). Esta situación se denomina borrado.
El código de copia de muestra es el siguiente:
clase Apple<T extiende Número>
{
talla T;
manzana pública()
{
}
Apple pública (tamaño T)
{
this.size = tamaño;
}
tamaño del conjunto vacío público (tamaño T)
{
this.size = tamaño;
}
público T getSize()
{
devolver este tamaño;
}
}
prueba de borrado de clase pública
{
principal vacío estático público (String [] argumentos)
{
Apple<Integer> a = nueva Apple<>(6);
// El método getSize de a devuelve un objeto entero
Entero como = a.getSize();
// Asigna el objeto a a la variable Apple, perdiendo la información de tipo entre corchetes angulares
manzana b = a; // ②
// b solo sabe que el tipo de tamaño es Número
Tamaño del número1 = b.getSize();
//El siguiente código provoca un error de compilación
Tamaño entero2 = b.getSize(); // ③
}
}