2011-11-18 14 views
5

Odkryłem następujące problemy z rodzajami. Rozważmy interfejs rodzajoweUzyskiwanie dostępu do argumentów typów generycznych używanych w typbundach

public interface A<X> { 
    X get(); 
    void doStuff(X x); 
} 

Teraz załóżmy następującą definicję metody:

public <T extends A<?>> void foo(T t) { 
    bar(t); 
} 

powodu zamiennika, informacje typu dla typu zwracanej get() jest niewystarczająca. Dlatego muszę przekazać do innego sposobu, który „wiąże” to wieloznaczny do nowego typu zmiennej:

private <X> void bar(A<X> t) { 
    X x = t.get(); 
    t.doStuff(x); 
} 

Wezwanie bar() w foo nie jest dozwolone, kompilator wyświetla się następujący komunikat o błędzie:

pasek metoda (A) w teście typu nie stosuje się do argumentów (T)

jeśli jednak zmienić foo() metoda do

public <T extends A<?>> void foo(T t) { 
    A<?> u = t; // No explicit cast required, no "unchecked" warning! 
    bar(u); 
} 

to działa. Czemu? Czy jest to błąd kompilatora? Wszelkie uwagi na ten temat będą bardzo mile widziane.

Uwagi:

  • Powodem dlaczego nie po prostu zadeklarować metodę void foo foo jako (A) jest to, że ja rzeczywiście przy górnej typu związanego interesection (&).
  • Powodem, dla którego nie deklaruję X jako zmiennej typu w foo(), jest fakt, że faktycznie mam problem na poziomie klasy i nie chcę niepotrzebnie zwiększać liczby parametrów typu tej klasy.
+0

używasz flagi -Xlint kompilator? Jeśli nie, spróbuj skompilować z tym –

+0

Nic nie zmienia. – misberner

+0

Zgadzam się z @kan. Kompilator java faktycznie to kompiluje. Użyłem 1.6.0_27. Eclipse podaje dokładny błąd, który podałeś, więc może go używasz? –

Odpowiedz

2

Sprawdziłem kod:

public class Test 
{ 
    public interface A<X> { 
     X get(); 
     void doStuff(X x); 
    } 
    public <T extends A<?>> void foo(T t) { 
     bar(t); 
    } 

    private <X> void bar(A<X> t) { 
     X x = t.get(); 
     t.doStuff(x); 
    } 
} 

to działa. javac 1.6.0_22. Gdzie masz błąd? Czy mogę użyć innego kodu?

+0

Dzięki, sprawdzę to w poniedziałek na moim komputerze w pracy, nie wiem dokładnie, której wersji javac używam. Właśnie przetestowałem to w domu i nie kompiluje używając javac 1.6.0_11 ... – misberner

+0

Btw, błąd po prostu jest " bar (Test.A ) w teście nie może być zastosowany do (T)", ze znacznikiem wskazując na wywołanie bar(). – misberner

1

Kod:

public class Test 
{ 
    public interface A<X> { 
     X get(); 
     void doStuff(X x); 
    } 
    public <T extends A<?>> void foo(T t) { 
     bar(t); 
    } 

    private <X> void bar(A<X> t) { 
     X x = t.get(); 
     t.doStuff(x); 
    } 
} 

kompiluje tylko dla wybranych wersji Java 1.6. Ten bug był zalogowany do Eclipse, ale został odrzucony z następującym wyjaśnieniem przez Srikanth Sankaran:

Uważam, że zachowanie Eclipse kompilator jest prawidłowa i jest dopasowana przez JDK5 i JDK7 (najnowsza). Wygląda na to, że zachowanie JDK6 jest regresją , która została naprawiona.

Zasadniczo, oto krótkie wyjaśnienie tego, co się dzieje tutaj:

Biorąc pod uwagę ogólną poprzeczkę metody i miejsca połączeń podane przez pasek (t), algorytm wnioskowania nie ma ograniczenia co do pracy z do określa typ zmiennej typu X. Po rozważeniu argumentów i oczekiwanego typu zwrotnego, X nadal pozostaje nierozwiązany i zgodnie z specyfikacją rozwiązuje się, że jest opublikowaną dolną granicą-i.e X wywnioskowano, że jest to obiekt , a metoda staje się pustym słupkiem (A) t); Ponieważ rzeczywistych parametrów nie można przekonwertować na parametry formalne, należy wnioskować o odrzuceniu metody , pozostawiając nas bez odpowiednich kandydatów. Dlatego połączenie musi zostać odrzucone.

Powód paska połączeń ((A) t); Udaje się, że w tym przypadku X jest rozumiane jako "przechwytywanie nr 1 z?" a ogólna metoda sparametryzowana tym podstawieniem staje się pustym słupkiem (A), dla którego zachowana jest kompatybilność parametrów.

Powiązane problemy