2010-10-15 13 views
9

Dies ist mein Code: Die ExecutorImp erweitert AbstractExecutor, die die gleichen ausführen Logiken seiner Implementierer (ExecutorImp ist ein Fall), beim Aufruf der Execute() -Methode von ExecutorImp, wird es die Methode in seinem Supertyp, aber der Supertyp aufrufen (der AbstractExcutor) sollte wissen, eine andere Klasse an den Implementierer Bindung (im Beispiel ist es die Benutzerklasse):Wie bekomme ich den generischen Typ zur Laufzeit?

import java.lang.reflect.InvocationTargetException; 
import java.util.ArrayList; 

abstract class AbstractExecutor<E> { 
    public void execute() throws Exception { 
     ArrayList<E> list = new ArrayList<E>(); 
     // here I want to get the real type of 'E' 
     Class cl = this.getClass().getTypeParameters()[0].getGenericDeclaration().getClass(); 
     Object o = cl.getConstructor(String.class).newInstance("Gate"); 
     list.add((E) o); 
     System.out.println(format(list)); 
    } 
    public abstract String format(ArrayList<E> list); 
    public abstract String getType(); 
} 

public class ExectorImp<E> extends AbstractExecutor<User> { 
    @Override 
    public String getType() { 
     return "user"; 
    } 
    @Override 
    public String format(ArrayList<User> list) { 
     StringBuffer sb = new StringBuffer(); 
     for (User u : list) { 
      sb.append(u.toString() + " "); 
     } 
     return sb.toString(); 
    } 
    public static void main(String[] args) throws Exception { 
     new ExectorImp().execute(); 
    } 
} 
class User { 
    String name; 
    public User(String name) { 
     this.name = name; 
    } 
} 

SO, was ist das Problem mit meinem Code?

+0

Vielleicht kann diese Antwort bei Ihrem Problem helfen. http: // Stapelüberlauf.com/questions/6624113/get-type-name-for-generic-parameter-of-generic-class/19454610 # 19454610 –

Antwort

12

Hier ist etwas Verwirrung. Aufgrund Typ Löschung können Sie keine Informationen von der Laufzeit parametrisierte Typ wie Typ erhalten:

Class<E> cls = E.getClass(); // Error. 
E e = new E(); // Error. 

Sie können jedoch compiletime parametrisierte Typinformationen aus der Klasse, Feld- und Methodendeklaration von ParameterizedType#getActualTypeArguments() erhalten.

abstract class AbstractExecutor<E> { 

    public void execute() throws Exception { 
     List<E> list = new ArrayList<E>(); 
     Class<E> cls = (Class<E>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
     E e = cls.getConstructor(String.class).newInstance("Gate"); 
     list.add(e); 
     System.out.println(format(list)); 
    } 

    // ... 
} 

aktualisieren:, ob dies empfohlen wird oder nicht, obwohl dies funktioniert, so empfindlich ist, Probleme der Laufzeit, wenn kleinere Änderungen in der Klassendeklaration auftreten. Sie als Entwickler sollten es richtig dokumentieren. Als eine völlig andere Alternative können Sie Polymorphie nutzen.

abstract class AbstractExecutor<E> { 

    public void execute() throws Exception { 
     List<E> list = new ArrayList<E>(); 
     E e = create("Gate"); 
     list.add(e); 
     System.out.println(format(list)); 
    } 

    public abstract E create(String name); 

    // ... 
} 

und implementieren UserExecutor entsprechend.

class UserExecutor extends AbstractExecutor<User> { 

    @Override 
    public User create(String name) { 
     return new User(name); 
    } 

    // ... 
} 
+0

Vielen Dank und vielen Dank für die Jungs auf dieser Seite. Die Antwort von BalusC ist, was ich wollte. Aber ich frage mich, ob mein Code empfohlen wird? Hier ist mein Applaction-Kontext: http: //forums.oracle.com/forums/message.jspa? MessageID = 7006003 # 7006003 – hguser

6

Ich denke, Sie sollten getActualTypeParameters verwenden; as getTypeParameters bezieht sich nicht auf das, was in Ihre aktuelle Instanziierung anstelle von E gesetzt wurde, sondern auf E selbst (um zu beschreiben, wie es begrenzt ist, etc.).

Um die ParameterizedType zu erhalten, sollten Sie zuerst verwenden.

Update: aber die oben funktioniert nur, wenn das aktuelle Objekt aus einer generischen Klasse mit dem generischen Argumente instanziiert, wie abgeleitet:

class StringList extends ArrayList<String> { 
    public Type whatsMyGenericType() { 
     return ((ParameterizedType)getGenericSuperClass()).getActualTypeParameters()[0]; 
    } 
} 
sollte

String.class zurückzukehren.

+4

Genau genommen: getGenericSuperclass() liefert nur dann aussagekräftige Ergebnisse für Sie, wenn die Klasse keine generische Klasse ist class, also: new LinkedList () .getClass(). getGenericSuperclass() wird nicht genug für Sie sein, aber: new LinkedList () {}. getClass(). getGenericSuperclass() ist OK - bemerkte den Unterschied? Durch Hinzufügen der {} habe ich die Unterklasse von LinkedList erstellt. – iirekm

+0

@Iirekm true, dann gibt es keine Möglichkeit für ein Objekt zu erkennen, wie es reflektiv deklariert wurde, aber es könnte "von außen" gemacht werden (mit 'Field.getGenericType()' zum Beispiel) ... – fortran

2

Ich glaube nicht, dass Sie den generischen Typ zur Laufzeit erhalten konnten. Der generische Typ ist eine Einschränkung, die zur Kompilierungszeit gilt. Wie ich mich zur Laufzeit erinnere, gibt es keinen Unterschied zwischen einer generischen Sammlung und einer Sammlung ohne einen generischen Typ.

+0

Nicht ganz wahr: Lies die Lösung mit 'Fortran' und meinem Kommentar dazu. – iirekm

+2

Er he, das dachte ich auch einmal ... Die Löschung bedeutet, dass man zur Kompilierzeit die generischen Einschränkungen ignorieren konnte, da der Bytecode, der beide Instanzen ausführt, derselbe ist, aber die Information darüber, wie die Instanzen deklariert wurden, bleibt erhalten. – fortran

1

Üblicher Ansatz, um das Problem zu beheben, ist es, den Code leicht zu ändern. Definieren Sie den Konstruktor für die Basisklasse und akzeptieren Sie den Parameter Class<E>. Ordnen Sie diesen Parameter dem internen Feld zu.

In der Unterklasse Konstruktor ohne Parameter definieren und super(User.class) von dort aufrufen.

Auf diese Weise werden Sie Klasse von Argument ohne viel Überlastung für Clients der Unterklassen wissen.

Verwandte Themen