Mam problem z nawigacją w regule Javy w celu wnioskowania o ogólnych parametrach typu. Rozważ następującą klasę, która ma opcjonalny parametr listy:
import java.util.Collections;
import java.util.List;
public class Person {
private String name;
private List<String> nicknames;
public Person(String name) {
this(name,Collections.emptyList());
}
public Person(String name,List<String> nicknames) {
this.name = name;
this.nicknames = nicknames;
}
}
Mój kompilator Java wyświetla następujący błąd:
Person.java:9: The constructor Person(String, List<Object>) is undefined
Ale Collections.emptyList()
powraca wpisać <T> List<T>
, nie List<Object>
. Dodanie obsady nie pomaga
public Person(String name) {
this(name,(List<String>)Collections.emptyList());
}
daje
Person.java:9: inconvertible types
Używanie EMPTY_LIST
zamiastemptyList()
public Person(String name) {
this(name,Collections.EMPTY_LIST);
}
daje
Person.java:9: warning: [unchecked] unchecked conversion
Podczas gdy następująca zmiana powoduje zniknięcie błędu:
public Person(String name) {
this.name = name;
this.nicknames = Collections.emptyList();
}
Czy ktoś może wyjaśnić, z jaką zasadą sprawdzania typu się tutaj spotykam i jaki jest najlepszy sposób obejścia tego? W tym przykładzie końcowy przykład kodu jest zadowalający, ale przy większych klasach chciałbym móc pisać metody zgodne z tym wzorcem „parametru opcjonalnego” bez powielania kodu.
Dla dodatkowego kredytu: kiedy należy używać, EMPTY_LIST
a nie używać emptyList()
?
źródło
Odpowiedzi:
Problem, z którym się spotykasz, polega na tym, że chociaż metoda
emptyList()
powracaList<T>
, nie podałeś jej z typem, więc domyślnie jest zwracanaList<Object>
. Możesz podać parametr type i sprawić, by kod działał zgodnie z oczekiwaniami, w następujący sposób:Teraz, gdy wykonujesz proste przypisanie, kompilator może określić ogólne parametry dla Ciebie. To się nazywa wnioskowanie typu. Na przykład, jeśli to zrobiłeś:
wtedy
emptyList()
połączenie poprawnie zwróci aList<String>
.źródło
this
musi być pierwszą instrukcją w konstruktorze.Chcesz użyć:
Jeśli spojrzysz na źródło tego, co pusta lista widzi, że tak naprawdę to po prostu
źródło
Metoda emptyList ma następujący podpis:
To, że
<T>
przed słowem Lista oznacza, że oblicza wartość parametru ogólnego T z typu zmiennej, do której przypisany jest wynik. Więc w tym przypadku:Zwracana wartość jest następnie jawnie przywoływana przez zmienną typu
List<String>
, dzięki czemu kompilator może ją rozgryźć. W tym przypadku:Kompilator nie ma wyraźnej zmiennej zwrotnej, której mógłby użyć do określenia typu ogólnego, więc domyślnie jest to
Object
.źródło