2009-08-10 16 views
5

Mam problem ze zrozumieniem rodzajowych Java i zostały uproszczone do tego przykładuJava okrągłe Generics

class A<T extends B> { 

    public void fun(T t) { 

    } 
} 

class B { 
    A a; 

    public void event() { 
     a.fun(this); 
    } 

} 

Problemem jest to, że generuje ostrzeżenie, ponieważ jest zdefiniowana wewnątrz B, ale już go używać jako rodzaj ogólny.

Mój pierwszy instynkt polegałby na tym, że mój projekt jest niewłaściwy, ale w tym przypadku nie mogę go zmienić. A jest jak kolekcja, a B jest jak węzeł w kolekcji, który użytkownicy mają zastąpić. Pewne wydarzenia mogą się zdarzyć w B, które wymagają zgłaszania powrotem do macierzystej A.

Ale ponieważ jest określone rodzajowo z B, w jaki sposób uniknąć ostrzeżenie kompilacji wewnątrz B.event()

Dzięki

+0

Jedyne ostrzeżenie jakie widzę to użycie A jako surowca. Jeśli nie jest to ostrzeżenie, do którego odnosisz się, podaj dokładniej i powiedz nam, jakiego kompilatora używasz. – skaffman

Odpowiedz

11

Kod

public class A<T extends B> { 
    public void fun(T t) { 
    } 
} 

public class B { 
    A<B> a; 

    public void event() { 
     a.fun(this); 
    } 
} 

ostrzeżenie zostanie pokonany.

Powód

Zmienne typu A powinny zostać uznane za pomocą specyficzny typ klasy, zgodnie z sugestią generycznego klasy podpisu (A<T extends B>).

Rozdzielczość

Mimo to postanawia ostrzeżenie kompilatora, podstawowy problem pozostaje. Laurence zapewnia doskonałe wyjaśnienie i rozwiązanie głównego problemu.

13

problemem jest to, że używasz typ surowca na tej linii:

A a; 

musisz określić typ parametru typ a jest (T).

Można zrobić coś takiego:

A<B> a; 

ale wówczas A może równie dobrze nie być rodzajowy w ogóle, jeśli mam zrozumienia swoje oświadczenie problemu. Prawdopodobnie chcesz zrobić coś takiego:

class A<T> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
}  

lub nawet poniżej:

class A<T extends B<? extends T>> { 
    public void fun(T t) { 

    } 
} 

class B<T extends B<T>> { 
    A<? super B<T>> a; 
    public void event() { 
    a.fun(this); 
    } 
} 

Istnieje kilka odmian w między te, które są ewentualnie przydatna również. Ten ostatni przykład jest najbardziej ogólny (ale oczywiście także najbardziej skomplikowany).

class A<T extends B<? extends T>> jest zapewnienie, że parametr typu do A to B. Ponieważ B jest sama rodzajowe i ma cykliczny że parametr typu skończyć się konieczności powiedzieć B<? extends T> (po prostu mówiąc T nie będzie działać tutaj).

The class B<T extends B<T>> jest tak blisko, jak można emulować "self type" w Javie. To pozwala B mówić o (prawie) konkretnym podtypie samego siebie. Podklasując B powiesz coś w stylu "class C extends <B<C>>". Jest to przydatne, ponieważ teraz typ C.a jest w rzeczywistości A<? super B<C>>.

Bit w tym ostatnim przykładzie jest użyteczny tylko wtedy, gdy planujesz połączenie B z A, który nie jest dokładnie tego samego typu, co B. Myśląc konkretnie, załóżmy, że masz A<Shape> i Circle (który rozszerza Shape, który rozszerza B). Super-wildcard pozwala używać ich razem. Bez niego potrzebowałbyś A<Circle>, a nie A<Shape> dla swojego Circle.

+0

To jest poprawne i świetny przykład symboli wieloznacznych. –