2015-07-29 6 views
3

J'ai ce code:Comment puis-je créer un tableau d'éléments dont les entrées ont des champs génériques?

import java.util.*; 
import java.lang.*; 
import java.io.*; 

class Main{ 
    public static void main (String[] args){ 
     Foo<String> foo = new Foo<String>(1000); 
    } 
} 

class Foo<Key extends Comparable<Key>>{ 
    private Entry[] a; 
    private class Entry{ 
     Key key; 
    } 
    public Foo(int size){ 
     a = (Entry[])new Object[size]; // <- this is the problem 
    } 
} 

quand je compile, je reçois une erreur, en disant:

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [LFoo$Entry; 
at Foo.<init>(Main.java:17) 
at Main.main(Main.java:7) 

J'ai essayé:

import java.util.*; 
import java.lang.*; 
import java.io.*; 

class Main{ 
    public static void main (String[] args){ 
     Foo<String> foo = new Foo<String>(1000); 
    } 
} 

class Foo<Key extends Comparable<Key>>{ 
    private Entry[] a; 
    private class Entry{ 
     Key key; 
    } 
    public Foo(int size){ 
     a = new Entry[size]; 
    } 
} 

Mais je suis une erreur en disant :

Main.java:17: error: generic array creation 
     a = new Entry[size]; 
      ^

Est-il possible de créer ce tableau du tout?

Répondre

2

Eh bien, vous pouvez réellement via reflection:

public class Main { 
    public static void main(String[] args) { 
     Foo<String> foo = new Foo<String>(1000); 
     foo.a[0] = foo.new Entry(); 
     foo.a[0].key = "ss"; 
    } 
} 

class Foo<Key extends Comparable<Key>> { 
    public Entry[] a; 

    public class Entry { 
     Key key; 
    } 

    public Foo(int size) { 
     a = (Entry[]) java.lang.reflect.Array.newInstance(Entry.class, size); 
    } 
} 
+0

Pourquoi ne peut pas faire cela par défaut? Cela ressemble à une douleur d'avoir à lancer et à écrire cet appel de méthode à long terme. – Pavel

+0

vous pouvez toujours faire 'import java.lang.reflect;' et écrire simple '... Array.newInstance (...' – Andremoniy

1

Il parce que Generics don't cope very well with arrays (à la compilation).

Vous devriez plutôt utiliser une collection, à la place:

class Foo<Key extends Comparable<Key>> { 
    private List<Entry> a; 

    private class Entry { 
     Key key; 
    } 

    public Foo(int size) { 
     a = new ArrayList<Entry>(size); 
    } 
} 
+0

Qu'en est-il de 'java.lang.reflect.Array.newInstance'? – Andremoniy

+0

Oui, l'approche avec Reflection est sympa, mais je préfère utiliser une collection, au lieu de faire de telles solutions. :) –

+0

Peut être il * doit * utiliser des tableaux, nous ne savons pas – Andremoniy

1

Je suis d'accord avec kocko que vous devez utiliser certains Collection au lieu de tableaux. Mais spécifiquement à votre point de vue, cela compile et fonctionne pour moi. Cela repousse simplement la responsabilité de créer le tableau à la méthode Array.newInstance. L'inconvénient est qu'il oblige le cast

class Foo<Key extends Comparable<Key>>{ 
    private Entry[] a; 
    private class Entry{ 
     Key key; 
    } 
    public Foo(int size){ 
     a = (Entry[])Array.newInstance(Entry.class,size); 
    } 
} 
+0

Je suis le premier :) – Andremoniy

+0

@Andremoniy Histoire de ma vie. : P – MadConan

0

Être une classe interne, du type Entry est à la portée du paramètre de type Key déclarée dans la classe externe. En d'autres termes, Entry est également générique.

Vous pouvez utiliser

a = (Entry[]) new Foo<?>.Entry[size]; 

ou l'équivalent brut (que je ne recommande pas)

a = (Entry[]) new Foo.Entry[size]; 

Ce type de array creation est expliqué dans le JLS

ArrayCreationExpression: 
    new ClassOrInterfaceType DimExprs [Dims] 

indiquant

Il est une erreur de compilation si le ClassOrInterfaceTypene désigne pas un type réifiable (§4.7).

reifiable type est

Un type est réifiable si et seulement si l'une des conditions suivantes est remplie:

  • Il fait référence à une déclaration de type classe non générique ou interface.
  • Il s'agit d'un type paramétré dans lequel tous les arguments de type sont des caractères génériques non bornés (§4.5.1).
  • Il s'agit d'un type brut (§4.8).
  • C'est un type primitif (§4.2).
  • Il s'agit d'un type de tableau (§10.1) dont le type d'élément est réifiable.
  • Il s'agit d'un type imbriqué où, pour chaque type T séparés par un ".", T est lui-même réifiable.

En utilisant le paramétrage avec un caractère générique ou le type brut, nous pouvons obtenir l'expression de la création du tableau présenté ci-dessus.