2013-10-26 13 views
5

Ich habe die folgende Schnittstelle für einen Einweiser, die ein Object zu einem DataNode Objekt Marshalls und zurück:Java Generics Vererbung

public interface DataMarshaller<T> { 

    /** 
    * returns the actual class that this marshaller is capable of marshalling. 
    * @return 
    */ 
    Class<T> getDataClass(); 

    /** 
    * marshalls the object to a DataNode 
    * 
    * @param object 
    * @return 
    */ 
    DataNode marshal(T object); 

    /** 
    * unmarshalls the object from a DataNode 
    * 
    * @param node 
    * @return 
    */ 
    T unMarshal(DataNode node); 

} 

Um sicher zu gehen, dass ich in der Lage das richtige Einweiser für ein Objekt zu bekommen I habe auch die Methode Class<T> getDataClass(), die ihre Klasse zurückgibt (die nach dem Kompilieren wegen Typlöschung verloren gegangen wäre).

Nun wollte ich diese Schnittstelle in einer Klasse implementieren, die Objekte Marschall vom Typ dieser Octree<T> wie in der Lage ist:

jetzt
public class OctreeMarshaller<T> implements DataMarshaller<Octree<T>> { 

    @Override 
    public Class<Octree<T>> getDataClass() { 
     return Octree.class; //<- compiletime error 
    } 

    @Override 
    public DataNode marshal(Octree<T> object) { 
     //... 
    } 

    @Override 
    public Octree<T> unMarshal(DataNode node) { 
     //... 
    } 


} 

Mein Problem ist, dass (natürlich) Octree.class ist nicht vom Typ Class<Octree<T>> sondern des nicht generischen Typs Class<Octree> und Java wird es mir nicht erlauben, es auf Class<Octree<T>> zu werfen.

Die Frage ist nun: Gibt es eine mehr elegent Art und Weise zu lösen als die beiden, die ich bereits in Betracht gezogen:

  • Änderung der Rückgabewert in der Schnittstelle Class<T>-Class<?>
  • Änderung der Klassen Unterschrift OctreeMarshaller zu public class OctreeMarshaller implements DataMarshaller<Octree>
+0

Nicht sicher, was Sie mit dem 'CLASS' Objekt für, aber vielleicht Super-Typ-Token sind wonach du suchst: http://gafter.blogspot.sk/2006/12/super-type-tokens.html. Sie sind eine Möglichkeit, "verschachtelte" generische Typen zur Laufzeit auszudrücken, obwohl Sie alle tatsächlichen Typüberprüfungen selbst implementieren müssen. (Das heißt, Sie erhalten nicht automatisch ein "intelligenteres" 'Class.cast()' oder irgendetwas.) – millimoose

Antwort

4

Ohne eine Instanz von Octree<T> können Sie kein Klassenobjekt vom Typ Class<Octree<T>> konstruieren. Da wir aber (aufgrund Typ Löschung) wissen, dass es nur eine Klasse Octree während der Laufzeit, dann ist es sicher zu schreiben

public class OctreeMarshaller<T> implements DataMarshaller<Octree<T>> { 

    @Override 
    @SuppressWarnings("unchecked") 
    public Class<Octree<T>> getDataClass() { 
     return (Class<Octree<T>>)(Class<?>)Octree.class; 
    } 

    [...] 
} 
+0

Das löste mein Problem. Ich habe nie daran gedacht, es zweimal zu werfen - also danke! :) – Entrusc

1

Mit Class eines generischen Typ, benötigen Sie einen Doppel Besetzung:

public Class<Octree<T>> getDataClass() { 
    return (Class<Octree<T>>)(Class<?>)Octree.class; 
} 

Whacky, aber es funktioniert.

+0

Aber Casting ist ein Widerspruch zur Typsicherheit – siledh