2013-03-15 9 views
25

Dlaczego kompilator jest w stanie poprawnie wywnioskować parametr typu String w przypadku zwracania typu funkcji.Wnioskowanie typu generics Java 7: wartość zwracana vs argument metody

public class Generics { 
    private static List<String> function() { 
     return new ArrayList<>(); 
    } 
} 

ale nie wtedy, gdy typ wywnioskować to parametr metoda:

public class Generics { 
    public static void main(String[] args) { 
     method(new ArrayList<>()); 
    }  

    private static void method(List<String> list) { 

    } 
} 

Błąd w tym przypadku jest:

The method method(List<String>) in the type Generics is not applicable 
for the arguments (ArrayList<Object>) 
+7

Ponieważ nie zawracali sobie głowy wdrażaniem wnioskowania o rodzajach, gdziekolwiek byłoby to możliwe. Nie testowałem tego konkretnego przypadku, ale Java 8 przynosi wiele ulepszeń dotyczących inferencji typów, aby pomóc w lambdach. –

+1

Dzieje się tak dlatego, że idealne wnioskowanie o typie jest zbyt trudnym zadaniem do rozwiązania w skończonym czasie (jest ono na tej samej kolejności złożoności co problem z zatrzymaniem). W związku z tym programiści Javy musieli narysować gdzieś linię. Jak zauważyli inni, ciągle przesuwają linię dalej, ale muszą istnieć pewne ograniczenia. –

+1

@KonstantinNaryshkin: praca wykonana na Javie 8 pokazuje, że narysowali linię na wcześniej. Bardziej użyteczne zasady * są * możliwe i * są integrowane * w Javie 8. Łatwo powiedzieć, że powinni byli popchnąć to dalej za pierwszym razem, ale ciężko jest przewidzieć, która dodatkowa praca przynosi rzeczywiste korzyści. W sumie początkowa implementacja była całkiem przydatna. Ale mogło to zostać wcześniej poprawione. –

Odpowiedz

16

Jest to jedno z miejsc, gdzie rodzaj wnioskowania jeszcze nie działa zgodnie z oczekiwaniami.

Niestety to zachowanie jest całkowicie poprawne i zgodne.

Dobrą wiadomością jest to, że Java 8 obejmie improved type inference (JEP 101), więc sytuacje takie jak ta powinny opracować tak, że można się spodziewać:

Wydaje się rozsądne, że kompilator powinien być w stanie ustalić typ gdy wynik takiego ogólnego wywołania metody przekazuje się innej metodzie [...].

Niestety, nie jest to dozwolone w JDK 5/6/7 - jedyną dostępną dla programisty opcją jest użycie jawnego argumentu typu.

Oprócz bezpośrednich ulepszeń (tj sytuacjach takich jak te, które można wymienić tutaj), zmiana ta jest również niezbędna do bycia w stanie bardziej efektywnie wykorzystywać Lambdas (JEP 126) (czyli bez konieczności wpisywania wielu informacji typu).

+0

Tak, mają w zasadzie dokładnie ten sam przykład, który został tam napisany. – aglassman

+2

Wygląda na to, że java 8 będzie większą wersją java od wersji 5. Niecierpliwie się z tym rozwinę. Ci, którzy wciąż muszą używać java 1.4, są w moich myślach. – gontard

6

Sekcja na inferring unresolved type arguments w JLS jest raczej skomplikowane, ale rozumie, że diament pierwszym przypadku występuje w miejscu, gdzie jest poddany konwersji przypisania, podczas gdy w drugim przypadku zachodzi to w sposobie konwersja inwokacji, która podlega innym regułom.