powiedzmy mamy klasę i przeciążenia funkcji:rozdzielczości przeciążenia odniesieniami metoda i specjalnościach interfejsu funkcja dla prymitywnych typów
public class Main {
static final class A {
}
public static String g(ToIntFunction<? extends A> f) {
return null;
}
public static String g(ToDoubleFunction<? extends A> f) {
return null;
}
}
i chcę zadzwonić g odniesieniem metoda funkcji typu A - > int:
public class Main {
static final class A {
}
public static String g(ToIntFunction<? extends A> f) {
return null;
}
public static String g(ToDoubleFunction<? extends A> f) {
return null;
}
private static int toInt(A x) {
return 2;
}
public static void main(String[] args) {
ToIntFunction<? extends A> f1 = Main::toInt;
ToDoubleFunction<? extends A> f2 = Main::toInt;
g(Main::toInt);
}
}
Działa z javac, ale nie z eclipse ecj. Przesłałem raport o błędzie do ecj, ale nie jestem pewien, czy jest to błąd typu ecj lub javac, i spróbowałem zastosować algorytm rozwiązywania przeciążenia, aby to zrozumieć. Mam wrażenie, że kod powinien zostać zaakceptowany, ponieważ intuicyjnie uzasadnione jest, że ToIntFunction
lepiej pasuje do toInt
niż ToDoubleFunction
. Jednak moje czytanie JLS polega na tym, że należy go odrzucić, ponieważ nie ma usprawiedliwienia dla bycia bardziej szczegółowym.
Muszę przyznać, że jestem trochę zagubiony w specyfikacji JLS i doceniłbym jakąś pomoc. Najpierw chciałam obliczyć typ Main::double2int
, więc przyjrzałem się 15.13.2. Type of a Method Reference. Nie określa typ, ale określa, kiedy typ jest zgodne w różnych kontekstach
Wyrażenie odniesienia sposób jest zgodny w kontekście przypisania, kontekście wywołania albo odlewanie związku z typem cel T jeśli T jest funkcjonalny typu interfejsu (§9.8), a ekspresja jest przystający podstawie rodzaju funkcji typu docelowego ziemia pochodzącego z T.
rodzaje mielone są ToIntFunction<A>
i ToDoubleFunction<A>
. toInt
zwraca wartość int, która jest zgodna z liczbą podwójną, więc mógłbym wywnioskować, że odwołanie do metody jest kompatybilne z ToIntFunction<? extends A>
i ToDoubleFunction<? extends A>
w kontekście wywołania. Można to zweryfikować, przypisując nazwę metody zarówno do ToIntFunction<? extends A>
, jak ii ToDoubleFunction<? extends A>
, która jest akceptowana w funkcji głównej.
Potem spojrzałem w rozdzielczości przeciążenia i znalazł 15.12.2.5. Choosing the Most Specific Method który ma szczególny przypadek o referencje metoda zdecydować, które z tych dwóch przeciążeń dla ToIntFunction
lub ToDoubleFunction
jest bardziej specyficzny dla parametru Main::toInt
deklaracji kompilacji A -> int
.
funkcjonalny typu interfejs S jest bardziej szczegółowy niż typu interfejsu funkcjonalnego T do wyrażenia E, jeżeli T nie jest podtypem S, a jedna z poniższych sytuacji (gdzie U1 ... UK i R1 są rodzaje parametrów oraz rodzaj zwrotny typu funkcji do chwytania S i V1 ... Vk i R2 są rodzaje parametrów oraz rodzaj typu funkcji T) zwracają:
...
Jeśli e jest dokładnym wyrażeniem referencyjnym metody (§15.13.1), następnie i) dla all i (1 ≤ i ≤ k), Ui jest takie samo jak Vi, i ii) jedno z następujących jest prawdziwe:
R2 jest nieważny.
R1 <: R2.
R1 jest typem pierwotnym, R2 jest typem odniesienia, a deklaracja czasu kompilacji dla odwołania do metody ma typ zwracany, który jest typem pierwotnym .
R1 jest typem odniesienia, R2 jest typem pierwotnym, a deklaracja czasu kompilacji dla odwołania do metody ma typ zwracany, który jest typem odniesienia .
Pierwszy warunek oczywiście nie pasuje, ponieważ R1 i R2 nie są nieważne.
dwa interfejsy ToIntFunction
i ToDoubleFunction
różni się tylko ich rodzaje, które obie są proste typy double
i int
. W przypadku typów pierwotnych klauzula "R1 <: R2" jest zdefiniowana w 4.10.1 zgodnie z rozmiarem typów. Nie ma relacji między double
i int
, więc ten przypadek nie określa, który typ jest bardziej szczegółowy.
Dwa ostatnie punkty również nie pasują, ponieważ żaden z dwóch funkcjonalnych interfejsów nie ma zwracanej wartości typu referencyjnego.
Wydaje się, że nie ma reguły dla przypadku, gdy dwa funkcjonalne interfejsy zwracają prymitywy, a kod powinien zostać odrzucony jako niejednoznaczny. Jednak javac akceptuje kod i oczekiwałbym, że to zrobi. Zastanawiam się więc, czy jest to brakujący punkt w JLS.
Przyjemny połów. I bardzo proste ... Więc wniosek będzie taki, że ToIntFunction lepiej pasuje niż ToDoubleFunction, a kod jest zgodny. W takim przypadku jest to błąd typu ecj. – Jens