Zacznijmy od 3 interfejsów. To, co robią, nie jest ważne. Zwróć uwagę, że samochód jest sparametryzowany(), natomiast Foo i Bar nie.Parametry powiązania w metodzie ogólnej kończą się niepowodzeniem, gdy działa równoważny interfejs ogólny, dlaczego?
interface Foo {void testFoo();}
interface Bar {void testBar();}
interface Car<A> {A testCar();}
chcę „kompozytowych” tych interfejsów, a to działa dobrze, jeśli jawnie tworzenia kompozytów tak:
interface FooBar extends Foo,Bar {}
interface FooCar<A> extends Foo,Car<A> {}
Jednak ja dużo wolę w sposób dorozumiany poprzez interfejsy kompozytowe ograniczone deklaracje typów różnych metod. Na przykład:
public <T extends Foo & Bar> T implicitFooBar() {return null;}
public <X, T extends Foo & Car<X>> T implicitFooCar() {return null;}
działa:implictFooBar() metoda zwraca typ T, który implementuje oba interfejsy i Foo Bar (kompozyt, jeśli będzie). Połączenie tego sposobu kompiluje i można uniknąć konieczności wyraźnie stwierdzenie interfejs fooBar:
// implicit composition of Foo and Bar, GOOD
FooBar implicitFooBar = implicitFooBar();
implicitFooBar.testFoo();
implicitFooBar.testBar();
niepowodzeniem: jednak wywołanie implicitFooCar() z kompilacją. Komunikat o błędzie jest „Metoda implicitFooCar() w typie GenericsTest nie dotyczy argumentów()” (I zawinięte moje kodu testu w klasie o nazwie GenericsTest.) Tylko
// implicit composition of Foo and Car<X>, FAIL!
//Compiler says "The method implicitFooCar() in the type GenericsTest is not applicable for the arguments()"
FooCar<Number> implicitFooCar = implicitFooCar(); //compile error on method call
implicitFooCar.testFoo();
Number n2 = implicitFooCar.testCar();
Błąd kompilatora pokazach gdy deklaracja typu jest złożona i sparametryzowana. Na przykład, zarówno tych kompilacji i można nazwać po prostu w porządku:
public <X> Car<X> justCar() {return null;}
public <X, T extends Car<X>> T implicitCar() {return null;}
pytanie ...
podejrzewam to ma coś wspólnego z typem skasowaniem, ale chciałbym zrozumieć szczegóły co tu się dzieje. Czytałem samouczki Oracle Generics, ale nie widzę jakiej kombinacji reguł metoda implicitFooCar() narusza, podczas gdy implicitFooBar() i implicitCar() są w porządku. Szukam wyjaśnienia w stylu akademickim, a nie tylko pracy.
Bonus
Co ciekawe, następujący wariant wywołanie implicitFooCar() metoda działa (brak błędów kompilatora.) Wskazuje na to, dlaczego druga wersja nie działa, ale mam jeszcze połączyć te kropki .
//variant... GOOD... but why?
implicitFooCar = this.<Number,FooCar<Number>>implicitFooCar();
Code Test (całość)
Jeśli chcesz grać z kodem, to jest tutaj jako jednej klasy.
public class GenericsTest {
public static interface Foo {void testFoo();}
public static interface Bar {void testBar();}
public static interface Car<A> {A testCar();}
public static interface FooBar extends Foo,Bar {}
public static interface FooCar<A> extends Foo,Car<A> {}
public <X> Car<X> justCar() {return null;}
public FooBar explicitFooBar() {return null;}
public <T extends Foo & Bar> T implicitFooBar() {return null;}
public <X> FooCar<X> explicitFooCar() {return null;}
public <X, T extends Foo & Car<X>> T implicitFooCar() {return null;}
public <X, T extends Car<X>> T implicitCar() {return null;}
public void test() {
justCar().testCar();
// explicit composition of Foo and Bar, GOOD
FooBar explicitFooBar = explicitFooBar();
explicitFooBar.testFoo();
explicitFooBar.testBar();
// explicit composition of Foo and Car<X>, GOOD
FooCar<Number> explicitFooCar = explicitFooCar();
explicitFooCar.testFoo();
Number n1 = explicitFooCar.testCar();
// implicit composition of Foo and Bar, GOOD
FooBar implicitFooBar = implicitFooBar();
implicitFooBar.testFoo();
implicitFooBar.testBar();
// implicit composition of Foo and Car<X>, FAIL!
//Compiler says "The method implicitFooCar() in the type GenericsTest is not applicable for the arguments()"
FooCar<Number> implicitFooCar = implicitFooCar(); //compile error on method call
implicitFooCar.testFoo();
Number n2 = implicitFooCar.testCar();
//variant... GOOD... but why?
implicitFooCar = this.<Number,FooCar<Number>>implicitFooCar();
// implicit (no composition) Car<X>, GOOD
Car<Number> implicitCar = implicitCar();
Number n3 = implicitCar.testCar();
}
}
UPDATE
To kompiluje z javac wersji 1.8.0_60 (i _45 za komentarze), ale Eclipse (wersja 4.4.2.M20150204-1700) wbudowane w kompilator ETS zgłasza błąd, o którym mowa powyżej. Dodałem znacznik zaćmienia do tego pytania, ponieważ może to być problem EJC.
Twój przykładowy kod u dołu kompiluje się dla mnie (Java 1.8.0_45). Jaka jest twoja wersja Java? – rgettman
Widzę, co próbujesz zrobić, ale to nie zadziała. W szczególności podpis, który napisałeś dla 'implicitFooBar', twierdzi, że dla każdego typu, który implementuje' Foo' i 'Bar', może zwrócić ten typ. To zadziała tylko, jeśli zwrócisz 'null'; nie zadziała, jeśli spróbujesz zwrócić rzeczywisty obiekt. System typu Java nie może wyrazić tego, co próbujesz zrobić. –
@LouisWasserman Dla tła ... Pracuję nad płynnym API. Wyraźne interfejsy zawierają listę dostępnych akcji w punktach w składni API, a niejawne interfejsy są wymagane, gdy wiele zestawów akcji jest możliwych w składni. Dobra uwaga dotycząca implementacji, która obecnie zwraca wartość null. Nie zacząłem kodować implementacji (po prostu tłumaczenie specyfikacji API do tej pory) i prawdopodobnie będę potrzebował tych pośrednich interfejsów w tym momencie. – allenru