2017-02-15 5 views
2

Ich versuche, so etwas zu tun:Java generische List <>

1. Ansatz

Type ty = entityType.getEntityClass(); // could be e.g. String.class 
List<ty> list; 

2. Ansatz

Class cl = entityType.getEntityClass(); // could be e.g. String.class 
List<cl> list; 

jedoch Compiler sagt einfach "Nein".

Gibt es eine Möglichkeit, den generischen Typ <T> von z.B. eine dynamische java.util.List nur, indem sie z. String.class oder foo.getClass()?

...

Was ich eigentlich bin versucht, eine Liste von einem bestimmten Parameter des Typs zu tun initialisiert EntityTypeEnum oder es ist Class Eigenschaftswert.

Konstruktive Kritik ist willkommen. Vielen Dank!

Anzahl: (als Antwort von Andy Kommentar)

Class cl = String.class; 
List<cl> list; 

..ist auch nicht arbeiten!

List<String> list; 

.. funktioniert natürlich.

Was ist also der Unterschied zwischen String und String.class?

Oder gibt es einen Weg, um den Wert zu setzen wie:

public enum EntityTypeEnum { 
    ARTICLE(Article) 
.. 
+4

"Allerdings Compiler sagt einfach "nein"." Denn dafür gibt es keine Generika. Sie dienen zum Erzwingen der Typsicherheit zur Kompilierzeit; Wenn Sie den Typ erst zur Laufzeit kennen, können Generika Ihnen nicht helfen. –

+0

Ich habe deinen Standpunkt verstanden. Stellen Sie sich vor, dass der Typ zum Zeitpunkt der Kompilierung bekannt ist: Class cl = String.class; Liste Liste; Es würde immer noch nicht kompiliert werden. –

+0

Technisch gesehen ist das kein kompilierbarer konstanter Ausdruck. Aber Sie können das einfach nicht: Generika können nicht auf der * Variable * basieren, sondern auf dem * Typ * der Variablen. –

Antwort

1

Es funktioniert nicht, weil Generics ein Kompilierungszeitkonzept sind, aber Sie versuchen, es als ein Laufzeitkonzept zu verwenden.

Der Unterschied besteht darin, dass der Compiler bei Kompilierungskonzepten in der Lage sein muss, den Typ anhand der Informationen zu ermitteln, die er in Ihrem Code hat (d. H. Ohne ihn auszuführen oder zu bewerten).

Dieser Code wäre syntaktisch korrekt:

public enum EntityTypeEnum 
{ 
    ARTICLE(String.class), // just using some builtin types to demonstrate 
    ORDER(Integer.class), 
    CUSTOMER(Double.class), 
    CUSTOMER_SESSION(Short.class); 

    private final Class<?> entityClass; 

    private EntityTypeEnum(final Class<?> entityClass) 
    { 
    this.entityClass = entityClass; 
    } 

    public Class<?> getEntityClass() 
    { 
    return this.entityClass; 
    } 
} 

class Test 
{ 
    // here, T is the type parameter which is determined from the class type 
    public <T> List<T> createList(final Class<T> clazz) 
    { 
    return new ArrayList<T>(); 
    } 

    // this is the demo code on how to use it  
    public void foo() 
    { 
    EntityTypeEnum t = EntityTypeEnum.ARTICLE; 
    List<?> list = createList(t.getEntityClass()); 
    } 
} 

Das Problem ist, dass dies nicht Ihnen viel hilft. Liste ist mehr oder weniger dasselbe wie Liste. Der Compiler kann den Typ nicht auf eine bestimmte enthaltene Objektklasse eingrenzen, da dies von der Laufzeit abhängt.

Für Ihren Fall, wenn Sie eine gemeinsame übergeordnete Klasse für Ihre Elemente haben, können Sie diese Informationen, um die Art zu verengen verwenden:

public enum EntityTypeEnum 
{ 
    ARTICLE(Article.class), 
    ORDER(OrderHeader.class), 
    CUSTOMER(Customer.class), 
    CUSTOMER_SESSION(CustomerSession.class); 

    private final Class<? extends CommonParent> entityClass; 

    private EntityTypeEnum(final Class<? extends CommonParent> entityClass) 
    { 
    this.entityClass = entityClass; 
    } 

    public Class<? extends CommonParent> getEntityClass() 
    { 
    return this.entityClass; 
    } 
} 

class Test 
{ 
    public <T extends CommonParent> List<T> createList(final Class<T> clazz) 
    { 
    return new ArrayList<T>(); 
    } 

    public void foo() 
    { 
    EntityTypeEnum t = EntityTypeEnum.ARTICLE; 
    List<? extends CommonParent> list = createList(t.getEntityClass()); 
    } 
} 

Aber wenn man einen gemeinsamen Elternteil hat, gibt es keinen Vorteil von der obiger Code über nur schreiben:

List<CommonParent> list = new ArrayList<CommonParent>(); 

und all die zusätzliche generischen Sachen Skipping ...

4

Sie sind Missverständnisse, was Java Generika sind in der Lage: Sie nicht etwas, basierend auf dem Wert einer Variablen tun, nur mit der Typ der Variablen.

Grundsätzlich sind Java-Generika nur eine Auswahl von Umwandlungen: Der Compiler fügt automatisch Umwandlungen für Sie ein und prüft, ob die Typen, die aus diesen Umwandlungen resultieren, übereinstimmen.


können Sie tun, was Sie in Ihrem Beispiel zu beschreiben, obwohl, irgendwie, nur nicht Aufzählungen verwenden. Einer der Nachteile von enums in Java ist, dass alle Elemente denselben Typ haben.

Statt eine echte Enum zu verwenden, können Sie etwas, das in etwa sieht aus wie ein Enum verwenden:

final class EntityTypeEnumIsh { 
    private EntityTypeEnumIsh() {} 

    static final EntityClassSupplier<Article> ARTICLE = 
    new EntityClassSupplier<>(Article.class); 
    static final EntityClassSupplier<OrderHeader> ORDER = 
    new EntityClassSupplier<>(OrderHeader.class); 
    // ... 

    final class EntityClassSupplier<T> { 
    private final Class<T> clazz; 

    EntityClassSupplier(Class<T> clazz) { this.clazz = clazz; } 

    Class<T> getEntityClass() { return clazz; } 
    } 
} 

Sie können nun diese in einem Verfahren verwenden, wie Sie beschreiben:

<T> List<T> method(EntityClassSupplier<T> supplier) { 
    return new ArrayList<>(); 
} 

und rufen dies wie:

List<Article> list = method(EntityTypeEnumIsh.ARTICLE); 

natürlich bekommt man nicht alle der Nettigkeit einer „echten“ Enumeration (wie Serialisierung, r Widerstand gegen Reflektionsattacken etc). Aber Sie bekommen etwas anderes nützliches, also wägen Sie es für Ihren Anwendungsfall ab.

Verwandte Themen