Création d'un tableau pour stocker les types génériques en Java [dupliquer]

Cette question a déjà une réponse ici:

Supposons que je dois créer un tableau qui stocke ArrayList d'entiers et la taille du tableau est 10.

Le code ci-dessous le fera:

ArrayList<Integer>[] pl2 = new ArrayList[10]; 

Question 1:

À mon avis, le code le plus approprié serait

ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10];    

Pourquoi cela ne fonctionne-t-il pas?

Question 2:

Les deux compilations ci-dessous

  1. ArrayList<Integer>[] pl2 = new ArrayList[10];
  2. ArrayList[] pl3 = new ArrayList[10];

Quelle est la différence en ce qui concerne la déclaration de référence de pl2 et pl3?

39
demandé sur Peter Mortensen 2013-05-07 13:08:12

11 réponses

Question 1:

Fondamentalement, cela est interdit par le langage Java. Ceci est couvert dans Spécification du langage Java pour les génériques .

Lorsque vous utilisez

ArrayList<Integer>[] pl2 = new ArrayList[10];    // warning

Vous obtenez l'avertissement du compilateur, car l'exemple suivant va compiler (générer un avertissement pour chaque ligne de code):

ArrayList wrongRawArrayList = new ArrayList();      // warning
wrongRawArrayList.add("string1");                   // warning 
wrongRawArrayList.add("string2");                   // warning  

pl2[0] = wrongRawArrayList;                         // warning 

, Mais maintenant vous tableau, censé contenir ArrayList de Integer, contient totalement faux ArrayList de String objets.

Question 2:

Comme il a déjà été répondu, la déclaration de p12 vous fournit une vérification du temps de compilation et vous libère de l'utilisation de la coulée lors de l'obtention d'éléments de votre ArrayList.

Exemple précédent légèrement modifié:

ArrayList<Integer>[] pl2 = new ArrayList[10];                // warning 

ArrayList<String> wrongArrayList = new ArrayList<String>();  // OK!
wrongArrayList.add("string1");                               // OK! 
wrongArrayList.add("string2");                               // OK!

pl2[0] = wrongArrayList;                                     // ERROR

Maintenant, puisque vous utilisez des génériques, cela ne compilera pas. Mais si vous utilisez

ArrayList[] pl2 = new ArrayList[10]; 

, Vous obtiendrez le même résultat que dans le premier exemple.

13
répondu Vladimir 2013-05-07 10:04:14

Les informations génériques ne comptent qu'au moment de la compilation, elles indiquent au compilateur quel type pourrait être placé dans un tableau, en cours d'exécution, toutes les informations génériques seront effacées, donc ce qui importe, c'est la façon dont vous déclarez le type générique.

Cité de penser en Java:

Il n'est pas exact de dire que vous ne pouvez pas créer de tableaux de les types génériques. Vrai, le compilateur ne vous laissera pas instancier un tableau d'un type générique. Cependant, il vous permettra de créer une référence à un tel tableau. Par exemple:

List<String>[] ls; 

Cela passe par le compilateur sans plainte. Et bien que vous impossible de créer un objet tableau réel contenant des génériques, vous pouvez créez un tableau du type non générifié et convertissez-le:

//: arrays/ArrayOfGenerics.java 
// It is possible to create arrays of generics. 
import java.util.*; 

public class ArrayOfGenerics { 
    @SuppressWarnings("unchecked") 
    public static void main(String[] args) { 
        List<String>[] ls; 
        List[] la = new List[10]; 
        ls = (List<String>[])la; // "Unchecked" warning 
        ls[0] = new ArrayList<String>(); 
        // Compile-time checking produces an error: 
        //! ls[1] = new ArrayList<Integer>(); 

        // The problem: List<String> is a subtype of Object 
        Object[] objects = ls; // So assignment is OK 
        // Compiles and runs without complaint: 
        objects[1] = new ArrayList<Integer>(); 

        // However, if your needs are straightforward it is 
        // possible to create an array of generics, albeit 
        // with an "unchecked" warning: 
        List<BerylliumSphere>[] spheres = 
           (List<BerylliumSphere>[])new List[10]; 
        for(int i = 0; i < spheres.length; i++) 
           spheres[i] = new ArrayList<BerylliumSphere>(); 
    } 
}

Une Fois que vous avez une référence à une Liste[], vous pouvez voir que vous obtenez une vérification à la compilation. Le problème est que les tableaux sont covariants, donc une Liste[] est aussi un Objet[], et vous pouvez les utiliser ceci pour assigner une ArrayList dans votre tableau, sans erreur lors de la soit le moment de la compilation ou de l'exécution.

Si vous savez que vous n'allez pas upcast et vos besoins sont relativement simples, cependant, il est possible pour créer un tableau de génériques, qui fournira la compilation de base la vérification de type. Cependant, un conteneur générique sera pratiquement toujours une meilleur choix qu'un tableau de génériques.

16
répondu ltebean 2013-05-07 14:11:40

Les Tableaux sont covariants. Cela signifie qu'ils conservent le type de leurs éléments à l'exécution. Les génériques de Java ne le sont pas. Ils utilisent l'effacement de type pour masquer essentiellement le casting implicite en cours. Il est important de comprendre que.

, Vous devez utiliser Array.newInstance()

En outre, les tableaux contiennent des informations de type type de Composant, c'est-à-dire sur le type des éléments contenus. Les informations de type d'exécution concernant le type de Composant sont utilisées lorsque les éléments sont stockés dans un tableau afin de s'assurer qu'aucun "étranger" les éléments peuvent être insérés.

Pour plus de détails, regardez ici

4
répondu Abimaran Kugathasan 2013-05-07 09:30:17

Cela ne fonctionne pas car Les classes génériques n'appartiennent pas aux Types Reifiable.

LesJLS sur L'expression de création de Tableau états:

C'est une erreur de compilation Si le [type de classe] ne désigne pas un type reifiable (§4.7). Sinon, le [type de classe] peut nommer n'importe quel type de référence nommé, même un type de classe abstrait (§8.1.1.1) ou un type d'interface (§9).

Les règles ci-dessus impliquent que le type d'élément dans une expression de création de tableau ne peut pas être un type paramétré, autre qu'un caractère générique non borné.

La définition des Types Reifiables est la suivante:

Comme certaines informations de type sont effacées lors de la compilation, tous les types ne sont pas disponibles au moment de l'exécution. Les Types qui sont complètement disponibles au moment de l'exécution sont appelés types reifiable.

Un type est reifiable si et seulement si l'un des éléments suivants contient:

It refers to a non-generic class or interface type declaration.

It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).

It is a raw type (§4.8).

It is a primitive type (§4.2).

It is an array type (§10.1) whose element type is reifiable.

It is a nested type where, for each type T separated by a ".", T itself is reifiable.

For example, if a generic class X<T> has a generic member class Y<U>, then the type X<?>.Y<?> is reifiable because X<?> is reifiable and Y<?> is reifiable. The type X<?>.Y<Object> is not reifiable because Y<Object> is not reifiable.
2
répondu alain.janinm 2013-05-07 15:01:41

Commençons d'abord par la question 2, puis revenons à la question 1:

Question 2:

> ArrayList [] pl2 = Nouveau ArrayList [10]; ArrayList [] pl3 = Nouveau ArrayList [10];

Quelle est la différence en ce qui concerne la déclaration de référence de p12 et p13 est concerné?

En pl2 assure une meilleure sécurité de type que p13.

Si j'écris pour pl2:

pl2[0]=new ArrayList<String>();

Il me donnera une erreur de compilateur indiquant " Impossible de convertir de ArrayList<String> à ArrayList<Integer>"

Ainsi, il assure la sécurité de la compilation.

Cependant, si j'écris pour p13

pl3[0]=new ArrayList<String>();
pl3[1]=new ArrayList<Integer>();

Il ne lancera aucune erreur et il incombera au développeur de coder et de vérifier correctement tout en extrayant les données de p13, pour éviter toute conversion de type dangereuse pendant l'exécution.

Question 1:

C'est probablement comme ça que les génériques fonctionnent. Lors de l'initialisation du tableau principal, ArrayList<Integer>[] pl2 = new ArrayList[10], le côté gauche, ArrayList<Integer>[] pl2, assurera la sécurité de type uniquement lorsque vous initialiserez le Objet ArrayList dans la position d'index:

pl2[0]=new ArrayList<Integer>();

La déclaration du tableau principal côté droit = new ArrayList[10] garantit simplement que la position de l'index contiendra les éléments de type ArrayList. Jetez également un oeil à des concepts d'effacement de type dans Type effacement pour plus d'informations.

2
répondu Rohit 2013-05-09 20:37:03

Question 1.

Eh bien, ce n'est pas la syntaxe correcte. Donc cela ne fonctionne pas.

Question 2.

ArrayList<Integer>[] pl2 = new ArrayList[10];
ArrayList[] pl3 = new ArrayList[10];

Puisque pl2 est défini avec le type générique au moment de la compilation, le compilateur saura que pl2 est seulement autorisé à avoir des entiers et si vous essayez d'attribuer quelque chose d'autre que des entiers, vous serez alerté et la compilation échouera.

En pl3 puisqu'il n'y a pas de type générique, vous pouvez attribuer n'importe quel type d'objet à la liste.

1
répondu pulasthi 2013-05-09 20:39:04
 ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10];

Signifie que vous n'avez pas besoin de lancer lorsque vous récupérez des données de ArrayList exemple dans le cas normal

 ArrayList[] pl2 = new ArrayList[10];
 pl2.put(new Integer(10));
 Integer i = p12.get(0);    // this is wrong
 Integer i = (Integer)p12.get(0);    // this is true with casting

Mais

 ArrayList<Integer>[] pl2 = new ArrayList<Integer>[10];   
 pl2.put(new Integer(10));
 Integer i = p12.get(0);    // this is true no need for casting
0
répondu aymankoo 2013-05-07 09:22:05

Les problèmes avec les génériques sont par défaut émis en tant qu'avertissement par le compilateur.

Après la compilation, à cause de l'effacement de type, ils deviennent tous ArrayList[] pl2 = new ArrayList[10], mais le compilateur vous avertit que ce n'est pas bon.

Les génériques ont été ajoutés à Java, et pour être rétrocompatible, vous pouvez utiliser générique avec non générique de manière interchangeable.

0
répondu Michal Borek 2013-05-09 20:31:30

Question1

Vous ne pouvez pas créer de tableaux de types paramétrés

Question 2

 ArrayList<Integer>[] pl2 = new ArrayList[10];

Cela signifie que vous dites au compilateur que vous allez créer un tableau qui stockera arraylist d'entiers. Votre arraylist ne contiendra que des objets entiers. C'est là que les génériques entrent en jeu. Les génériques rendent votre code plus sûr et fiable. Si vous êtes sûr que votre liste ne doit contenir que des objets entiers, vous devriez toujours aller de l'avant avec cela.

Mais quand vous dites

 ArrayList[] pl3 = new ArrayList[10];

Cela signifie arraylist peut stocker n'importe quel type d'objet comme string, integer, objets personnalisés, etc.

0
répondu M Sach 2013-05-09 20:33:32

Il semble que vous ne pouvez pas créer un tableau de arraylists avec un type générique, selon une réponse à la question de débordement de pile Créer un tableau d'éléments ArrayList.

0
répondu Genjuro 2017-05-23 12:30:21

Pour autant que je sache, en Java, il n'y a pas de génériques. En termes de types, ArrayList<Integer> and ArrayList sont les mêmes choses.

Java utilise l'effacement de type pour les génériques. Cela signifie que toutes les informations de type sur le générique sont effacées au moment de la compilation. Alors ArrayList<Integer> devenez ArrayList.

Donc c'est juste un truc à la compilation. Je devine, pour éviter toute confusion ou erreur que le programmeur pourrait faire, ils ont permis à ArrayList<Integer>[] d'être instancié comme ceci: new ArrayList[10].

Donc un ArrayList<Integer>[] et un ArrayList[] sont les même chose parce que les informations entre parenthèses sont effacées au moment de la compilation.

0
répondu Alecu 2013-05-09 20:44:35