2009-04-08 6 views
5

Ich habe eine Basisklasse mit einer abstrakten getType() -Methode. Ich möchte, dass Unterklassen diese Methode implementieren und die tatsächlich zu verwendende Klasse bereitstellen können.Geben Sie einen verschachtelten Klassentyp in Java zurück

Im Code in etwa wie folgt:

public abstract class A { 
    public static interface Tile; 

    protected abstract Class<Tile> getTileClass(); 
} 

public class B extends A { 
    public static class MyTile implements A.Tile { } 

    @Override 
    protected abstract Class<A.Tile> getTileClass() { 
     MyTile t = new MyTile(); // WORKS 
     return MyTile;   // ERROR HERE 
    } 
} 

Das Problem hier ist, dass ich markierte in der Zeile "MyTile kann nicht aufgelöst werden". Also versuche ich, diese stattdessen zurück.

Rückkehr neue MyTile() getClass()

aber jetzt von Eclipse sagt mir:

Typenkonflikt: Konvertierung von Klasse < erfassen # 1-von? erstreckt B.MyTile > Klasse < A.Tile >

, die ich nicht einmal sicher bin, ob vielleicht ein Fehler in Eclipse gibt es hier oben (Capture # 1?).

Als nächstes gebe ich Interfaces auf und versuche, eine abstrakte Tile-Basisklasse zu verwenden. Mit etwas Hilfe von Eclipse beende ich mit dem folgenden Code auf, die zu kompilieren scheint:

public abstract class A { 
    public static abstract class Tile; 

    protected abstract Class<? extends Tile> getTileClass(); 
} 

public class B extends A { 
    public static class MyTile exends A.Tile { } 

    @Override 
    protected abstract Class<? extends A.Tile> getTileClass() { 
     return new MyTile().getClass(); // WORKS 
     return MyTile;     // "Cannot be resolved" 
    } 
} 

Also im Grunde scheine ich drei Fragen zu haben:

1) Ist es möglich, dies mit A zur Arbeit zu kommen .Tile als Schnittstelle?

2) Bei Verwendung einer Basisklasse ist Class<? extends X> wirklich der richtige Weg?

3) Und wie kann ich meine verschachtelte B.MyTile-Klassenreferenz innerhalb der Methode zurückgeben? new MyTile().getClass() zu tun, kann nicht stimmen, oder?

+0

Wahrscheinlich ist es eine schlechte Idee, ein 'Class' anstelle eines nicht reflektierenden Objekts zurückzugeben. –

+0

@Tom Bei der Rückgabe einer Klasse im Kontext der geprüften Typen handelt es sich um ein sehr häufiges Muster, mit dem Sie den * checked * -Typ z. B. einer Sammlung zur Laufzeit überprüfen können. Ich kenne keinen anderen Weg, in der Tat ... – Varkhan

Antwort

6

Generische und kovariante Überlagerung funktionieren nicht sehr gut zusammen. Sie müssen getTileClass() explizit deklarieren, indem Sie eine Klasse zurückgeben, die eine Unterklasse von A.Tile sein kann.

Sie können auch auf das Klassenobjekt von MyTile zugreifen, ohne es mit MyTile.class zu instanziieren.

Versuchen Sie stattdessen:

public abstract class A { 
    public static interface Tile; 

    protected abstract Class<? extends Tile> getTileClass(); 
} 

public class B extends A { 
    public static class MyTile implements A.Tile { } 

    @Override 
    protected Class<MyTile> getTileClass() { 
     return MyTile.class; 
    } 
} 

Noch besser wäre ein generisches zu machen. Sie haben noch erstreckt in der Klasse Typdefinition verwenden, aber Sie können etwas genauer sein:

public abstract class A<T extends A.Tile> { 
    public static interface Tile; 

    protected abstract Class<? extends T> getTileClass(); 
} 

public class B extends A { 
    public static class MyTile implements A.Tile { } 

    @Override 
    protected Class<MyTile> getTileClass() { 
     return MyTile.class; 
    } 
} 
+0

wahrscheinlich Copy & Paste-Fehler, aber kann eine abstrakte Methode einen Körper haben? Korrekt sollte sein "geschützt Klasse getTileClass {..." –

+0

@Carlos ja, das war ein übereifriger c/p – Varkhan

+0

Gute Antwort. Ist das ein Problem nur wegen der Kovarianz oder allgemein? – Uri

-1
public abstract class A { 
    public static interface Tile {}; 

    // I return something that is-a Tile 
    protected abstract Tile getTileClass(); 
} 

public class B extends A { 
    public static class MyTile implements A.Tile { } 

    @Override 
    protected abstract Tile getTileClass() { 
     return new MyTile(); 
    } 
} 

Keine Notwendigkeit für Generika, Sie wollen einfach nur sagen, dass Sie eine Tile zurückgeben oder Tile Unterklasse.

Übrigens ist eine öffentliche statische Schnittstelle in einer Klasse ein "Code-Geruch"; machen Sie es entweder schreibgeschützt, so dass nur Unterklassen von A Tile implementieren können, oder legen Sie es in eine eigene Top-Level-Schnittstelle. Indem man es eingibt, aber jedem erlaubt, es zu implementieren, sendet man eine gemischte Nachricht.

Verwandte Themen