2015-07-29 11 views
9

Poniżej mój kodDlaczego następujący kod z Cyclic Generics nie jest kompilowany?

class A<B2 extends B, A2 extends A<B2, A2>> { 
    C<B2, A2> c; 

    void test() { 
     c.acceptParameterOfTypeA(this); 
    } 

} 

class B { 

} 

class C<B2 extends B, A2 extends A<B2, A2>> { 
    void acceptParameterOfTypeA(A2 a) { 

    } 
} 

Błąd występuje w c.acceptParameterOfTypeA(this);.

Błąd jest

Metoda acceptParameterOfTypeA (A2) w typu C nie ma zastosowanie dla argumentów (A)

Z tego co widzę, metoda acceptParameterOfTypeA oczekuje parametr typu A i this w wierszu z błędem jest typu A.

Co robię źle? Jak rozwiązać ten problem?

Jeśli jego ważne, używam Java8

+2

'klasa B {' tam, parametr 'A' wygląda na surowo. – EpicPandaForce

+0

@EpicPandaForce tak, myślę, że mam zły przykład. Spróbuję sprawdzić, czy mogę poprawić. Dzięki! –

+0

@EpicPandaForce dzięki, zaktualizowałem pytanie z faktycznym scenariuszem, z którym stoję. –

Odpowiedz

8

będę znowu zmieniać nazwy klas, tak, że wszystko jest bardziej czytelne. Więc zróbmy:

public class First<T extends Second, U extends First<T, U>> { 
    Third<T, U> c; 

    void test() { 
     c.acceptParameterOfTypeA(this); 
    } 

} 

class Second { 

} 

public class Third<X extends Second, Y extends First<X, Y>> { 
    void acceptParameterOfTypeA(Y a) { 

    } 
} 

Z definicji członka c (Third<T, U>), możemy stwierdzić, że c narazi metodę z tym podpisem:

void acceptParameterOfTypeA(U a) { .. } 

Co jest U? U jest podtypem First<T, U>.

Ale jeśli U można podstawić First po typu skasowaniem, będzie to oznaczać, że First extends First<T, First>, co nie jest prawdą, ponieważ U oznacza podtypu First, który jest parametryzowane z pewnych konkretnych podtypów Second i First.

Aby dostać się do U, można zastosować tzw Get This podejście.

Po pierwsze, ponieważ trzeba U, który jest podtypem First, ale nie może uzyskać go od First można wprowadzić metodę, która zwraca abstract go:

abstract class First<T extends Second, U extends First<T, U>> { 
    Third<T, U> c; 

    void test() { 
     c.acceptParameterOfTypeA(getU()); 
    } 

    abstract U getU(); 

} 

Następnie zaimplementować próbkę podklasa First zwany Fourth, która rozciąga First z konkretne typy do T i U, na przykład:

class Fourth extends First<Second, Fourth> { 
    Fourth getU() { 
     return this; 
    } 
} 

W metodzie getU() po prostu wykonaj return this;, ponieważ zwróci ona prawidłowy zamiennik U w super-klasie.

Więcej informacji:

1

Mówiąc najprościej, c.acceptParameterOfTypeA() akceptuje A2. this ma typ A<B2, A2>, który nie jest znany z rozszerzenia A2. Wiadomo tylko, że A2 rozciąga się na A<B2, A2>.

1

podstawie odpowiedzi kocko „s, oryginalne pytanie miałem to samo rozwiązanie:

public class Main { 
    abstract class A<A2 extends A<A2, B2>, B2 extends B<A2, B2>> { 
     B2 b; 

     void test() { 
      b.testMethod(getThis()); //getThis() instead of this; 
     } 

     abstract A2 getThis(); 
    } 

    class B<A2 extends A<A2, B2>, B2 extends B<A2, B2>> { 
     void testMethod(A2 a) { 

     } 
    } 

    public void execute() { 

    } 

    public static void main(String[] args) { 
     Main main = new Main(); 
     main.execute(); 
    } 
} 
1

Możemy uprościć usuwając B część, która nie przyczynia się do problemu -

class A<T extends A<T>> 
{ 
    void test(C<T> c) 
    { 
     c.acceptParameterOfTypeA(this); // ERROR 
    } 
} 

class C<T extends A<T>> 
{ 
    void acceptParameterOfTypeA(T a) {} 
} 

this typ to A<T>; i pytanie brzmi, czy A<T> <: T, która jest fałszywa.

To, czego naprawdę chcemy, to "self type", więc typ this to T. Nie mamy tego w Javie.

Zazwyczaj używamy T extends A<T> dla "self type"; ale w niektórych przypadkach jest wadliwy i nieadekwatny.

Jednym ze sposobów na to jest T getThis(), jak wspomniał Kocko.

Można po prostu zrobić brutalną obsadę (T)this, która jest oczywiście poprawna z intencją T.


Moje preferowane podejście jest po prostu pominąć związany z T i zmień jego nazwę na This wskazać cel zmiennej typu. Przesyłanie (This)this wygląda oczywiście poprawne. Zobacz mój inny post. Takie podejście zwykle działa; ale to nie działa tutaj, ponieważ C potrzebowałby This, aby związać A<This>. Im głębszy problem, A i C, zależy od siebie nawzajem, co może zostać przeprojektowane.

+0

' (T) to 'jest niebezpieczne – user102008

Powiązane problemy