2008-12-20 18 views
9

Supongamos que tengo esto:¿Cuál es la alternativa más fácil a una matriz genérica en Java?

class test<T> 
{ 
    private T[] elements; 
    private int size; 
    public test(int size) 
    { 
     this.size = size; 
     elements = new T[this.size]; 
    } 
} 

Parece que esto no es posible debido a que el compilador no sabe qué constructor para llamar una vez que se intenta reemplazar el código genéricos o algo así. Lo que me pregunto es, ¿cómo voy a hacer esto? Me imagino que es posible, dado lo fácil que es hacerlo en C++.

Editar: Lo siento Olvidé la [] en la declaración de elementos.

Respuesta

0

puedo estar equivocado, pero su declaración parece extraño, ¿no debería tener:

private T[] elements; 
13

El problema es que, dado que el parámetro de tipo genérico T se transforma en Object por el compilador (se llama Tipo borrado), realmente se crea una matriz de Object. Lo que puede hacer es proporcionar un Class<T> a la función:

class test<T> 
{ 
    private T[] elements; 
    private int size; 
    public test(Class<T> type, int size) 
    { 
     this.size = size; 
     elements = (T[]) Array. newInstance(type, size); 
    } 
} 

Usted encontrará una mejor exlanation de aquí: Angelika Langer - Can I create an array whose component type is a type parameter?

8

El alternativa más fácil de una matriz genérica es el uso de una lista.

+0

Estoy de acuerdo - Las listas son generalmente una mejor alternativa por muchas razones. De hecho, algunas personas sugerirán que las matrices se deben considerar como una parte obsoleta del lenguaje en Java 5+. No digo que soy uno de ellos ... pero encontrarás esa opinión. –

+0

Las matrices siguen siendo válidas para tipos primitivos. Pero para los tipos de referencia es solo una optimización inapropiada casi todo el tiempo. –

2

Hay dos soluciones que no requieren pasar en el objeto de la clase. En ambos supongo que, dado que es una variable privada, usted es la única persona que le agrega cosas, y el mundo exterior no lo ve.

Una es simplemente usar una matriz de Objeto simple Object[]. La desventaja es que perderá los beneficios de los genéricos y tendrá que lanzar cosas que salen de él, lo que hace que el código sea más feo. Pero ya que eres la única persona que pone cosas en él, entonces el reparto siempre debe estar seguro. El exterior no necesita saber qué está pasando.

Las otras opciones son como un truco. Crea un Object[] y luego lo "lanza" al T[]. Técnicamente esto es ilegal, porque Object[] y T[] son tipos de tiempo de ejecución diferentes y el primero no se puede convertir a este último. Pero siempre que no pase la matriz fuera de la clase (por ejemplo, la devuelva o algo así), entonces no causará ningún problema, ya que T[] se borrará a Object[] de todos modos, y no se realizará ningún lanzamiento. Luego puede obtener los beneficios de los genéricos en su clase para una codificación más fácil, pero debe tener mucho cuidado de no pasar esa matriz a nadie que realmente espere un T[], porque no lo es.

3

Tiendo a evitar arreglos básicos y uso ArrayLists (o similar Lists) siempre que sea posible por varias razones. Los dos más importantes son:

  1. No necesito la semántica de la matriz calva. No hay nada acerca de la notación de corchetes (es decir, la abreviatura de la aritmética del puntero) que me hace la vida más fácil.

  2. Si utilizo Listas, me estoy preparando para usar estructuras más sofisticadas habilitadas por concurrencia en la línea, según sea necesario. Por ejemplo, es muy fácil reemplazar un ArrayList con un CopyOnWriteArrayList.

Así, la escritura de su ejemplo usando un ArrayList genérica sería algo como esto:

campo
class test<T> { 
    /** It's not strictly necessary to make this a List vs. an ArrayList 
     You decide what interface you really need to expose internally. */ 
    private List<T> elements; 
    /** This parameter isn't necessary with a List. You can always call the 
     size() method instead. */ 
    private int size; 
    public test(int size) { 
     this.size = size; 
     elements = new ArrayList<T>(); 
     // Note that the next line isn't strictly necessary. 
     // An ArrayList can be dynamically resized without any real effort on your part. 
     elements.ensureCapacity(size); 
    } 
} 
0

El tamaño parece redundante. Podrías tener elements.length en lugar de size.

class Test<T> { 
    private final T[] elements; 
    public test(int size) { 
     elements = (T[]) new Object[size]; 
    } 
} 

O podría reemplazar la clase de prueba con una ArrayList. es decir, descartar la clase por completo.

+0

esto arrojará una excepción ya que la nueva matriz no es del tipo T []. – pdeva

+0

@pdeva: no, no lo hará; mientras permanezca dentro de la clase Prueba, no arrojará ninguna excepción porque la eliminación de T [] es Objeto []; pero debes tener cuidado de que no se vaya de la clase – newacct

0

mirada también a este código:

public static <T> T[] toArray(final List<T> obj) { 
    if (obj == null || obj.isEmpty()) { 
     return null; 
    } 
    final T t = obj.get(0); 
    final T[] res = (T[]) Array.newInstance(t.getClass(), obj.size()); 
    for (int i = 0; i < obj.size(); i++) { 
     res[i] = obj.get(i); 
    } 
    return res; 
} 

Convierte una lista de cualquier tipo de objeto a una matriz del mismo tipo.

Cuestiones relacionadas