2016-02-18 12 views
9

mam tej klasy:Jak związany typ klasy podklasy

public abstract class Addressable { 

    abstract <T extends "this" Addressable> void hardEquals(T t); 

} 

metody hardEquals (T t) nie jest ograniczony, jak chcę. To, czego chcę, to powiązanie T do tej samej klasy this. Innymi słowy, kiedy rozszerzenie klasy Addressable, z betonu klasy MyAddressable chcę, że metoda hardEquals() ma podpis:

void hardEquals(MyAddressable t); 

Dla kompletności:

public class MyAddressable extends Addressable { 

    void hardEquals(MyAddressable t); 

} 
  1. jest to możliwe do osiągnięcia czego chcę?
  2. Jeśli odpowiedź brzmi "nie", czy jest tak głupia, że ​​moja klasa jest więzią?
+0

Nie można tego poprawnie zrobić, ponieważ oznacza to, że 'MyAddressable' nagle otrzymuje metodę, która akceptuje' Adresowalny' zamiast innego typu, którego klasa nie jest przygotowana do obsługi, '' ten ''typ, jeśli istnieje, może być użyty tylko w kontekście takim jak '? extends this', jak pokazuje to sygnatura 'getClass()'. – Ferrybig

Odpowiedz

2

Generalnie nie jest to możliwe. Problem staje się jasny, gdy myśl trochę dłużej o swoim scenariuszu. Masz klasę Addressable i jej metodę hardEquals, która wymaga, aby jej parametr miał typ równy temu. Masz podklasę, która wydaje się działać zgodnie z przeznaczeniem. Teraz wyobraź sobie podklasę podklasy:

public class GrandChild extends MyAddressable { 
    void hardEquals(MyAddressable t); 
} 

Tutaj masz klasę, która musi zaakceptować MyAddressable jako hardEquals parametr ', ponieważ nie może przesłonić metodę przez zwężenie typy parametrów, czyli nie przyjmując rzeczy że superklasa została zaakceptowana. W końcu zawsze możesz mieć zmienną typu MyAddressable, która faktycznie odnosi się do instancji GrandChild. Nie można ograniczyć parametrów do hardEquals, aby dopasować rzeczywisty typ środowiska wykonawczego obiektu.

Tak więc pożądany "typ parametru musi odpowiadać this" konflikt reguł z "podklas metody musi akceptować wszystkie parametry, które nadklasy" reguły.


Należy pamiętać, że często jest to mylone z faktycznym ograniczeniem systemu typu, że to samo nie działa w przypadku typów zwrotu. Ponieważ rodzaje powrotne dozwolone mają być zawężony do podklasy, chęć gwarancji powrotu typ this może być uzasadnione w niektórych sytuacjach, na przykład:

class Base { 
    Base/*actually this type*/ clone() { … } 
} 
class SubClass extends Base { 
    SubClass/*actually this type*/ clone() { … } 
} 
class GrandChild extends SubClass { 
    GrandChild/*actually this type*/ clone() { … } 
} 

działa, ale nie ma formalnego sposób określić gwarancję, że this Typ jest zwracany, więc do dyscypliny programisty należy dodać poprawne przesłonięcie każdej podklasy.

Ale, jak powiedział, dla typów parametr to nie działa ogólnie, ponieważ nie można zawęzić typu parametru w podklasie.

1

Można pożyczyć trick z Comparable i określ typ rodzajowy w deklaracji klasy samego:

public abstract class Addressable<T> { 
    abstract <T> void hardEquals(T t); 
} 

Powoduje definicji lekko przylegający klasowych, ale powinna ona spełniać swoje wymagania

public class HomeAddress extends Addressable<HomeAddress> { 
    void hardEquals(HomeAddress t) { 
     // implementation 
    } 
} 
1

Nie jestem świadomy czystego rozwiązania Twojego problemu.

Można pomyśleć o czymś takim:

public abstract class Addressable<T extends Addressable<T>> { 

    abstract void hardEquals(T other); 

} 

public class MyAddressable extends Addressable<MyAddressable> { 

    @Override 
    void hardEquals(MyAddressable other) { 
    // ... 
    } 

} 

Ale to może zawieść w niektórych przypadkach, np:

public class FakeAddressable extends Addressable<MyAddressable> { 

    @Override 
    void hardEquals(MyAddressable aT) { 
    // ... 
    } 

} 
1

Jeśli szukasz hardEquals które mogą tylko być wykorzystane z obiektami dokładnie tego samego typu, to coś takiego powinno zadziałać:

public abstract class Addressable<T extends Addressable<T>> { 

    abstract boolean hardEquals(T t); 

} 

class X extends Addressable<X> { 

    @Override 
    boolean hardEquals(X t) { 
     return true; 
    } 

} 

class Y extends Addressable<Y> { 

    @Override 
    boolean hardEquals(Y t) { 
     return true; 
    } 

} 

public void test() { 
    X x = new X(); 
    if (x.hardEquals(x)) { 
     System.out.println("Ok"); 
    } 
    Y y = new Y(); 
    // Fails! 
    if (x.hardEquals(y)) { 
     System.out.println("Not OK"); 
    } 
} 

Jak słusznie zauważa J.Holger - nie pomaga to w rozszerzaniu podklas.

+1

Ale teraz pomyśl o podklasach "Y" ... – Holger

Powiązane problemy