Hice una revisión de código para mi colega hace dos días. Sentí que no tenía una buena comprensión de Java Generics, así que saqué el libro "Java efectivo" 1 y luego miré los capítulos relevantes. En el ítem 24: eliminar la sección de advertencias sin control, el autor usa el método público <t> t [] toArray (t [] a) en la clase ArrayList como un ejemplo para ilustrar cómo usar la anotación de @SupessWarnings para variables.
ArrayList es una clase genérica, que se declara así:
Javapublic Class ArrayList <E> extiende AbstractList <E> Lista de implementos <E>, RandomAccess, Clonable, Java.io.Serializable
El método ToArray (t [] a) de esta clase es un método genérico, que se declara e implementa así:
@SupplesSwarnings ("no controlado") public <t> t [] toArray (t [] a) {if (a.length <size) // haz una nueva matriz del tipo de tiempo de ejecución de A, pero mi contenido: return (t []) arrays.copyOf (elementData, size, a.getClass ()); system.arrayCopy (elementData, 0, a, 0, size); size); tamaño) a [size] = null; return a;} Este método en realidad se declara en la interfaz de colección. Debido a que a menudo lo usamos a través de ArrayList, usaremos ArrayList como ejemplo aquí.
1 ¿Por qué se declara como un tipo diferente?
Mi pregunta es: ¿por qué este método utiliza el tipo T en lugar del tipo E de ArrayList? Es decir, ¿por qué este método no se declara así:
Javapublic e [] toArray (e [] a);
Si los tipos son los mismos, el error de tipo de parámetro se puede encontrar durante la compilación. Si los tipos son diferentes, es fácil generar errores de tiempo de ejecución. Por ejemplo, el siguiente código:
// Cree una ArrayListList <String> strlist = new ArrayList <String> (); strlist.add ("ABC"); strlist.add ("xyz"); // Convierta la lista STRLIST en una matriz de números. Tenga en cuenta que no hay errores de compilación en la siguiente declaración. Número [] numArray = strlist.toarray (nuevo número [0]); Ejecute el código anterior y la línea 6 lanzará una excepción de Java.Lang.ArrayStoreException.
Si el método ToArray usa el Tipo E, la Declaración 2 generará un error de compilación. Los errores de compilación son más amigables que los errores de tiempo de ejecución. Además, el objetivo principal de los genéricos es eliminar los errores de conversión de tipo (ClassCastException) durante la compilación. Este método es lo contrario. ¿Es este un gran error? Me he encontrado con un error de Java, pero aún no puedo creerlo.
Después de revisar Internet, este problema se ha discutido muchas veces 2, 3, 4.
2 puede mejorar la flexibilidad
Esta declaración es más flexible y puede convertir elementos en la lista actual en una variedad de tipos más generales. Por ejemplo, el tipo de lista actual es entero, y podemos convertir sus elementos en una matriz de números.
List <Integer> intlist = new ArrayList <Integer> (); intlist.add (1); intlist.add (2); número [] numArray = intlist.toarray (nuevo número [0]);
Si este método se declara como Tipo E, el código anterior tendrá un error de compilación. Parece que sería más apropiado declarar el método de la siguiente manera:
Javapublic <t super e> t [] toArray (t [] a);
Sin embargo, la sintaxis como <t Super E> no existe en Java. E incluso si existe, no funciona para las matrices. También es por esta razón que cuando se usa este método, incluso si T es la clase principal de E, o T es la misma que E, Java.Lang.ArraySteReException 5, 6, 7 no se puede evitar por completo. Consulte los siguientes dos códigos. En el primer código, T es la clase principal de E, y en el segundo código, T es lo mismo que E. Ambas piezas de código de tiro.
Código 1:
List <Integer> intlist = new ArrayList <Integer> (); intlist.add (1); intlist.add (2); Float [] floatArray = new float [2]; // float es una subclase de número, por lo que float [] es una subclase del número [] número [] numArray = floatArray; // La siguiente declaración lanzará una excepción de ArrayStoreException numArray = intlist.toarray (numArray);
Código 2:
List <Number> intlist = new ArrayList <Number> (); // El tipo de lista es el número. Pero el número es una clase abstracta, y solo puede almacenar instancias de su subclase intlist.add (new Integer ()); intlist.add (nuevo entero ()); Float [] floatArray = new float []; // float es una subclase de número, por lo que float [] es una subclase de número [] número [] numArray = floatArray; // La siguiente declaración lanzará una excepción de ArrayStoreException numArray = intlist.toarray (numArray);
Las excepciones anteriores son causadas por este hecho: si A es la clase principal de B, entonces A [] es la clase principal de B []. Todas las clases en Java heredan del objeto, y el objeto [] es la clase principal de todas las matrices.
Esta publicación 8 da un ejemplo, que muestra que incluso si el tipo de este método se declara como E, la ArrayStoreException no se puede evitar.
Esta excepción también se menciona en la documentación para este método:
ArrayStoreException si el tipo de tiempo de ejecución de la matriz especificada no es un supertipo del tipo de tiempo de ejecución de cada elemento en esta lista.
3 Puede ser compatible con versiones antes de Java 1.5
Este método apareció antes de la introducción de genéricos en Java (Generics se introdujo en JDK1.5). Fue declarado en ese momento:
Objeto javapublic [] toArray (objeto [] a)
Después de que aparezca genéricos, muchas clases y métodos se vuelven genéricos. Este método también lo declara así:
Javapublic <T> t [] ToArray (t [] a)
Esta declaración es compatible con versiones anteriores a Java 1.5.
4 algunas palabras más
Este método requiere un parámetro de matriz. Si la longitud de esta matriz es mayor o igual al tamaño de la lista actual, los elementos en la lista se almacenarán en la matriz; Si la longitud de esta matriz es menor que el tamaño de la lista actual, se creará una nueva matriz y los elementos en la lista actual se almacenarán en la matriz recién creada. Para mejorar la eficiencia, si es posible, la longitud de la matriz aprobada debe ser mayor o igual que el tamaño de la lista para evitar crear una nueva matriz mediante este método.
List <Integer> intlist = new ArrayList <Integer> (); intlist.add (); intlist.add (); // Pegar en una matriz, su longitud es el número [] numArray = intlist.toarray (nuevo número []); // Declaración // Pegue en una matriz, su longitud es igual a la longitud del número intlist [] numArray = intlist.toarray (nuevo número [intlist.size ()]); //Declaración
Además, la matriz como parámetros no puede ser nulo, de lo contrario se lanzará una nullpointerexception.
Notas al pie:
1
Java efectivo (2ª edición)
2
Enlace
3
Enlace
4
Enlace
5
Enlace
6
Enlace
7
Enlace
8
Enlace
9
Enlace
10
Enlace
Creado: 2016-04-06 Mié 21:14
EMACS 24.5.1 (Modo ORG 8.2.10)
Validar
El contenido anterior es la razón por la cual el tipo de parámetro de Java ArrayList.toarray (t []) el método introducido por el editor es T en lugar de E. Espero que sea útil para todos!