2008-12-20 3 views
9

Supposons que j'ai ceci:Quelle est l'alternative la plus simple à un tableau générique en Java?

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

Il semble que ce n'est pas possible car le compilateur ne sait pas ce constructeur pour appeler une fois qu'il tente de remplacer le code ou quelque chose génériques. Ce que je me demande, c'est comment je vais faire ça? J'imagine que c'est possible, étant donné que c'est facile en C++.

Editer: Désolé j'ai oublié le [] dans la déclaration des éléments.

Répondre

0

Je peux me tromper, mais votre déclaration semble étrange, ne devrait pas vous avoir:

private T[] elements; 
13

Le problème est que depuis le paramètre de type générique T est transformé en Object par le compilateur (il est appelé de type effacement), vous créez réellement un tableau de Object. Ce que vous pouvez faire est de fournir un Class<T> à la fonction:

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); 
    } 
} 

Vous trouverez un meilleur exlanation de celui-ci ici: Angelika Langer - Can I create an array whose component type is a type parameter?

8

Le plus facile alternative à un tableau générique est d'utiliser une liste.

+0

Je suis d'accord - Les listes sont généralement une meilleure alternative pour plusieurs raisons. En fait, certaines personnes suggèrent que les tableaux doivent être considérés comme une partie déconseillée du langage dans Java 5+. Je ne dis pas que je suis l'un d'entre eux ... mais vous trouverez cette opinion. –

+0

Les tableaux sont toujours valides pour les types primitifs. Mais pour les types de référence, c'est juste une optimisation inappropriée presque tout le temps. –

2

Deux solutions ne nécessitent pas de passer dans l'objet de classe. Dans les deux cas, je suppose que puisque c'est une variable privée, vous êtes la seule personne à y mettre des choses, et le monde extérieur ne le voit pas.

Il suffit d'utiliser un simple tableau d'objets Object[]. L'inconvénient est que vous perdrez les avantages des génériques et vous devrez jeter les choses qui en sortent, ce qui rend le code plus laid. Mais puisque vous êtes la seule personne à y mettre des choses, la distribution devrait toujours être sûre. L'extérieur n'a pas besoin de savoir ce qui se passe.

Les autres options sont une sorte de piratage. Vous créez un Object[], puis "cast" à T[]. Techniquement, cela est illégal, car Object[] et T[] sont des types d'exécution différents et le premier ne peut pas être moulé à ce dernier. Mais tant que vous ne passez pas le tableau hors de la classe (par exemple, le renvoyer ou quelque chose), cela ne causera aucun problème car T[] sera effacé de Object[] de toute façon, et aucune conversion n'est réellement effectuée. Alors vous pouvez obtenir les avantages des génériques dans votre classe pour faciliter le codage, mais vous devez faire extrêmement attention de ne pas passer ce tableau à quiconque s'attend réellement à un T[], parce que ce n'est pas le cas.

3

J'ai tendance à éviter les réseaux de base et utiliser ArrayLists (ou similaire Lists) autant que possible pour un tas de raisons. Les deux plus importants sont:

  1. Je n'ai pas besoin de la sémantique du tableau chauve. Il n'y a rien sur la notation de parenthèse (c'est-à-dire, raccourci pour l'arithmétique de pointeur) qui me facilite la vie. Si j'utilise les listes, je me configure pour utiliser des structures plus sophistiquées compatibles avec la concurrence sur la ligne, selon les besoins. Par exemple, il est facile de remplacer un ArrayList par un CopyOnWriteArrayList.

Ainsi, l'écriture de votre exemple en utilisant un ArrayList générique ressemblerait à quelque chose comme ceci:

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

Le champ de taille ne semble redondante. Vous pourriez simplement avoir des éléments.length au lieu de la taille.

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

Vous pouvez également remplacer la classe Test par une ArrayList. c'est-à-dire laisser tomber la classe tout à fait.

+0

cela lancera une exception puisque le nouveau tableau n'est pas de type T []. – pdeva

+0

@pdeva: non ce ne sera pas; tant qu'il reste dans le test de classe, il ne lancera aucune exception car l'effacement de T [] est Object []; mais vous devez faire attention à ne pas le laisser quitter la classe – newacct

0

Regardez aussi à ce code:

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; 
} 

Il convertit une liste de tout type d'objet à un tableau du même type.

Questions connexes