Matrices genéricas en Java
Bien, he estado buscando en Google en la web y parece que no puedo encontrar ninguna solución a mi problema. Encontré muchas soluciones, pero ninguna que encajara.
Necesito crear una variedad de genéricos. Pero el tipo genérico en sí se extiende Comparable. Cuando intento lo siguiente:
public class Hash<T extends Comparable<String>> {
private T[] hashTable;
private int tableSize;
Hash(int records, double load) {
tableSize = (int)(records / loadFactor);
tableSize = findNextPrime(tableSize);
hashTable = (T[])(new Object[tableSize]); //Error: Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
}
}
El problema es que el Objeto no se puede convertir en un genérico que extienda Comparable. ¿Hay alguna forma de evitar esto?
Básicamente, los genéricos y las matrices no se mezclan. La respuesta corta es que puede solucionar este problema. La respuesta más larga es que probablemente no deberías y te explicaré por qué.
Podrías usar Array.newInstance()
así:
private Comparable[] hashtable;
...
hashtable = (Comparable[])Array.newInstance(Comparable.class, tableSize);
pero no puedes crear una matriz de tu tipo parametrizado.
Las matrices son covariantes . Eso significa que conservan el tipo de sus elementos en tiempo de ejecución. Los genéricos de Java no lo son. Utilizan el borrado de tipos básicamente para enmascarar la conversión implícita que se está produciendo. Es importante entender eso.
Entonces, cuando crea una matriz de objetos, no puede convertirla, por ejemplo, en una matriz comparable (o cualquier otro tipo) porque eso no es correcto.
Para darle un ejemplo. Con los genéricos esto es perfectamente legal:
List<String> list = new ArrayList<String>();
List<Integer> list2 = (List<Integer>)list;
list.add(3);
También es por eso que no puedes hacer esto:
public <T> T newInstance(T t) {
return new T(); // error!
}
es decir, en tiempo de ejecución no se conoce la clase de T. Es por eso que el código anterior se escribe más a menudo como:
public <T> T newInstance(T t, Class<T> clazz) {
return clazz.newInstance();
}
porque no hay ningún tipo de tiempo de ejecución para el argumento genérico. Pero con matrices:
String arr[] = new String[10];
Integer arr2[] = (Integer[])arr; // error!
Lo que deberías hacer en este caso (en mi humilde opinión) no es usar matrices sino usar un archivo ArrayList
. Honestamente, hay muy pocas razones para usar matrices en lugar de an ArrayList
y los genéricos son solo un ejemplo de eso.
Para obtener una explicación mejor y más completa, consulte las (excelentes) preguntas frecuentes sobre genéricos de Java :
¿Puedo crear una matriz cuyo tipo de componente sea un tipo parametrizado concreto?
No, porque no es seguro para tipos.
Las matrices son covariantes, lo que significa que una matriz de referencias de supertipo es un supertipo de una matriz de referencias de subtipo. Es decir,
Object[]
es un supertipo deString[]
y se puede acceder a una matriz de cadenas a través de una variable de referencia de tipoObject[]
....
Las otras respuestas aquí generalmente recomiendan un mejor enfoque para esto (especialmente la recomendación de usar un ArrayList en su lugar), pero una respuesta simple en este caso específico podría ser hacer:
hashTable = (T[])(new Comparable[tableSize]);
(es decir, cree una matriz de tipo raw Comparable en lugar de Object)
Si encapsula correctamente todo el acceso a esta matriz dentro de su objeto Hash, esto debería funcionar, pero (como explican las otras respuestas) podría quedar vulnerable.