2013-08-03 21 views
12

Das ist schwer zu erklären, aber ich habe überall nachgesehen, und ich konnte keine gute Antwort finden.Wie kann ich auf den Typ der aktuellen Klasse verweisen?

Ich habe auch Stack-Überlauf Fragen How can I refer to the class type a interface is implementing in Java? und How do I return an instance of an object of the same type as the class passed in using Java 6?, aber sie konnten nicht beantworten meine Frage gesehen. Beim Anwenden der Vererbung gibt es eine Ausnahme.

Es ist ein Beispiel, um es einfacher zu verstehen:

Sagen wir, ich habe einige Schnittstelle namens SelfMaker:

public interface SelfMaker <SELF>{ 
    public SELF getSelf(); 
} 

And A haben einen Hund, der mit anderen Hunden fortzupflanzen kann. So ist der Hund ein „SelfMaker“, wie folgt aus:

public class Dog implements SelfMaker<Dog> { 
    String color; 

    public String toString() { 
     return "some " + color + " dog"; 
    } 

    public Dog procreate(Dog anotherDog) { 
     Dog son = getSelf(); 
     son.color = color; 
     return son; 
    } 

    @Override 
    public Dog getSelf() { 
     return new Dog(); 
    } 
} 

Aber dann, ich habe eine DomesticDog, die ein Hund ist, aber es hat eine schöne Familie, die ihm benannt. Wie folgt aus:

public class DomesticDog extends Dog { 
    private String name; 

    public String toString() { 
     return super.toString() + " named " + name; 
    } 
} 

Nun, ich einige Klassen, die Paare der Dinge behandelt, die „SelfMaker“ s sind, lassen Sie sich diese Klasse „Couple“ nennen. Wie folgt aus:

public class Couple<T extends SelfMaker<T>> { 
    private T first; 
    private T second; 

    public String toString() { 
     return first.toString() + " and " + second.toString(); 
    } 
} 

DIE AUSNAHME:

Die Ausnahme kommt, wenn ich ein paar DomesticDog s erstellen möchten. Wie folgt aus:

public class CoupleOfDomesticDogs extends Couple<DomesticDog>{ 
    public DomesticDog procreate(){ 
     DomesticDog son = first.procreate(second); 
     return son; 
    } 
} 

Dies wird eine Ausnahme auf <DomesticDog> Beschweren werfen: Bound mismatch: The type DomesticDog is not a valid substitute for the bounded parameter <T extends SelfMaker<T>> of the type Couple<T>

Ich habe bereits versucht, die generalisierte Variable aus Klasse Paar zu, das zu ändern: Couple<T extends SelfMaker<?>> aber der „Sohn“ nicht sein, DomesticDog (und ich möchte, dass der "Sohn" ein DomesticDog ist). Wenn ich ein Cast hinzufüge, wird es kompiliert, aber es wird weniger lesbar sein.

Also ... hier ist die Frage: Gibt es einen Weg, dies ohne Castings und Verallgemeinerungen zu erreichen?

+0

bezogen werden: [Gibt es eine Möglichkeit, um den aktuellen Typ mit einem Typ Variable zu verweisen?] (Http://stackoverflow.com/ questions/7354740/is-there-a-way-to-to-the-current-type-with-a-type-Variable) –

+0

Die Klasse der aktuellen Klasse ist this.getClass(). Der Klassenname lautet this.getClass(). GetName(). Das ist so gut wie es geht. Und es gibt keine Möglichkeit, einen Cast in Java dynamisch festzulegen. –

Antwort

7

Es gibt keine Möglichkeit, dass ich denke, ohne Gießen zu tun. Ihr Problem wird gelöst werden, wenn Sie die procreate und getSelf Methoden der DomesticDog außer Kraft setzen und die Deklaration der Klasse Paares als solche ändern:

public class DomesticDog extends Dog { 
    private String name; 

    public DomesticDog procreate(Dog anotherDog) { 
     return (DomesticDog)super.procreate(anotherDog); 
    } 

    public Dog getSelf() { 
     return new DomesticDog(); 
    } 

    public String toString() { 
     return super.toString() + " named " + name; 
    } 
} 

public class Couple<T extends SelfMaker<? super T>> { 
    protected T first; 
    protected T second; 

    public String toString() { 
     return first.toString() + " and " + second.toString(); 
    } 
} 

Wenn Sie nicht wollen, getSelf() in jeder Unterklasse von Dog außer Kraft zu setzen, Sie die folgende Änderung in der Klasse Hund könnte:

public Dog getSelf() { 
    Class<? extends Dog> thisClass = this.getClass(); 
    try { 
     return thisClass.newInstance(); 
    } catch (InstantiationException e) { 
    } catch (IllegalAccessException e) { 
    } 
    throw new UnsupportedOperationException(thisClass 
         + " does not supply a public no-arg constructor"); 
} 

Dies garantiert, dass jeder Wert zurückgegeben von getSelf() ist eine Instanz von this.getClass(). Aber Sie müssten immer noch den Rückgabewert von procreate() für Unterklassen umsetzen. Es gibt keine Möglichkeit, einen Rückgabetyp explizit als this.getClass() anzugeben.

+0

das ist ziemlich schlau. Aber ... gibt es keine Möglichkeit, sich auf den Typ der Klasse zu beziehen? das würde meinen Code viel passender machen – Bengalaa

+2

Nein, man kann nicht explizit auf die Laufzeitklasse von "this" mit Generics verweisen, es sei denn man benutzt Platzhalter oder Casting. Siehe meine Bearbeitung oben. –

+0

Alle diese Ideen umgehen das Typsystem und verlassen sich darauf, dass der Programmierer das Richtige tut, ohne dass der Compiler es überprüfen kann. – newacct

0

Sie müssen Dog generisch und abstrakt machen, mit einem Typparameter, der das Ergebnis von getSelf() anzeigt.Jede Art von Dog müssen dann diese als Parameter mit sich selbst implementieren:

public abstract class Dog<T> implements SelfMaker<T> { 
    String color; 

    public String toString() { 
     return "some " + color + " dog"; 
    } 

    public T procreate(T anotherDog) { 
     T son = getSelf(); 
     son.color = color; 
     return son; 
    } 

} 

public class DomesticDog extends Dog<DomesticDog> { 
    private String name; 

    public String toString() { 
     return super.toString() + " named " + name; 
    } 

    @Override 
    public DomesticDog getSelf() { 
     return new DomesticDog(); 
    } 
} 
+0

Aber was, wenn du auch Dog Objekte machen willst? Oder was, wenn Sie DomesticDog erweitern möchten, um eine Unterkategorie von DomesticDogs zu erstellen? –

Verwandte Themen