¿Cómo puedo crear una matriz genérica en Java?
Debido a la implementación de genéricos de Java, no puedes tener un código como este:
public class GenSet<E> {
private E a[];
public GenSet() {
a = new E[INITIAL_ARRAY_LENGTH]; // Error: generic array creation
}
}
¿Cómo puedo implementar esto manteniendo la seguridad de tipos?
Vi una solución en los foros de Java que dice así:
import java.lang.reflect.Array;
class Stack<T> {
public Stack(Class<T> clazz, int capacity) {
array = (T[])Array.newInstance(clazz, capacity);
}
private final T[] array;
}
¿Qué está sucediendo?
A cambio, tengo que hacer una pregunta: ¿está GenSet
"marcado" o "no marcado"? ¿Qué significa eso?
Comprobado : escritura fuerte .
GenSet
sabe explícitamente qué tipo de objetos contiene (es decir, su constructor fue llamado explícitamente con unClass<E>
argumento, y los métodos generarán una excepción cuando se les pasen argumentos que no sean de tipoE
. ConsulteCollections.checkedCollection
.-> en ese caso, deberías escribir:
public class GenSet<E> { private E[] a; public GenSet(Class<E> c, int s) { // Use Array native method to create array // of a type only known at run time @SuppressWarnings("unchecked") final E[] a = (E[]) Array.newInstance(c, s); this.a = a; } E get(int i) { return a[i]; } }
Sin marcar : escritura débil . En realidad, no se realiza ninguna verificación de tipos en ninguno de los objetos pasados como argumento.
-> en ese caso, deberías escribir
public class GenSet<E> { private Object[] a; public GenSet(int s) { a = new Object[s]; } E get(int i) { @SuppressWarnings("unchecked") final E e = (E) a[i]; return e; } }
Tenga en cuenta que el tipo de componente de la matriz debe ser el borrado del parámetro de tipo:
public class GenSet<E extends Foo> { // E has an upper bound of Foo private Foo[] a; // E erases to Foo, so use Foo[] public GenSet(int s) { a = new Foo[s]; } ... }
Todo esto es el resultado de una debilidad conocida y deliberada de los genéricos en Java: se implementaron mediante borrado, por lo que las clases "genéricas" no saben con qué tipo de argumento fueron creadas en tiempo de ejecución y, por lo tanto, no pueden proporcionar tipos de argumento. seguridad a menos que se implemente algún mecanismo explícito (verificación de tipo).
Puedes hacerlo:
E[] arr = (E[])new Object[INITIAL_ARRAY_LENGTH];
Esta es una de las formas sugeridas de implementar una colección genérica en Effective Java; Artículo 26 . Sin errores de tipo, no es necesario convertir la matriz repetidamente. Sin embargo , esto genera una advertencia porque es potencialmente peligroso y debe usarse con precaución. Como se detalla en los comentarios, esto Object[]
ahora se hace pasar por nuestro E[]
tipo y puede causar errores inesperados ClassCastException
si se usa de manera insegura.
Como regla general, este comportamiento es seguro siempre que la matriz de conversión se use internamente (por ejemplo, para respaldar una estructura de datos) y no se devuelva ni se exponga al código del cliente. Si necesita devolver una matriz de tipo genérico a otro código, la Array
clase de reflexión que menciona es el camino correcto a seguir.
Vale la pena mencionar que siempre que sea posible, será mucho más feliz trabajando con List
s en lugar de matrices si usa genéricos. Ciertamente, a veces no tienes otra opción, pero usar el marco de colecciones es mucho más sólido.