2015-03-02 20 views
19

Używam Androida Studio 1.1.0.Niezaznaczone ostrzeżenie o przypisaniu

ta nie powoduje ostrzeżenie:

public static class A { 
    public Map<Integer, String> getMap() { 
     return null; 
    } 
} 

public static class B { 
    public void processA(A a) { 
     Map<Integer, String> map = a.getMap(); 
    } 
} 

Ale upewnij A Generic:

public static class A<T> { 
    public Map<Integer, String> getMap() { 
     return null; 
    } 
} 

i ten wiersz:

Map<Integer, String> map = a.getMap(); 

dostaje ostrzeżenie teraz: "Unchecked assignment: 'java.util.Map to java.util.Map<java.lang.Integer, java.lang.String>'.

Mimo że podpis getMap jest całkowicie niezależny od T, a kod jest jednoznaczny w odniesieniu do typów zawartych w Map.

wiem, że mogę pozbyć się ostrzeżenia przez reimplementing processA następująco:

public <T> void processA(A<T> a) { 
    Map<Integer, String> map = a.getMap(); 
} 

Ale dlaczego miałbym to robić? Co w ogóle ma tutaj znaczenie?

Więc pytanie brzmi - dlaczego trzeba wpisać skasowaniu nie tylko wpływa T (co jest zrozumiałe - jeśli jestem przechodzącej wystąpienie A, T jest nieznany), ale również „na sztywno” rodzajowy podpis jak <Integer, String> w tym przypadku?

Odpowiedz

13

W swoim drugim przypadku, gdy robisz:

public void processA(A a) 

Co masz na myśli przez A? Czy to oznacza A<String> lub A<List<String>> lub co? Być może nie używasz niczego związanego z typem A, ale hej kompilator nie wie o tym fakcie. Dla kompilatora, tylko A jest oznaką paniki.

W twoim przypadku, ponieważ nie specjalnie trzeba znać typ można:

public void processA(A<?> a) { 
    Map<Integer, String> map = a.getMap(); 
} 

uwzględniając typ argumentu A<?> środków, nie specjalnie obchodzi typ A i po prostu określić dzika karta. Dla ciebie oznacza to: każdy obiekt z A z dowolnego typu, jak zrobiłby to typ ogólny. W rzeczywistości oznacza to, że nie znasz typu. Jest bezużyteczny, ponieważ nie można zrobić niczego związanego z A w sposób bezpieczny dla użytkowników, jak ? może być praktycznie wszystko!

Ale jak na swoje ciało metody, to sprawia, że ​​cały sens w świecie, aby korzystać A<?> bo nie ma gdzie w organizmie rzeczywiście trzeba typ A

+0

'Nie może używać czegokolwiek związanego typu A , ale hej kompilator nie wie tego faktu "- cóż, to * może * poznać go dość łatwo, wystarczy rzucić okiem na implementację' processA', nietrudno sprawdzić, czy 'T' jest nieistotne;) Pójdę z '' jak sugerujesz, ale jestem rozczarowany kompilatorem. –

+0

@KonradMorawski W idealnym świecie, po prostu "A" powinno być nielegalne, a kod nie powinien się kompilować. Ale jest to dozwolone ze względu na kompatybilność wsteczną. Dla klasy zadeklarowanej jako "A ", jej rodzaj ogólny jest niezwykle ważny, aby zrobić cokolwiek związanego z 'A'. Tak więc po prostu użycie 'A' nie powinno być dozwolone (w rzeczywistości w Scali używanie tylko' A' jest nielegalne) – Jatin

+0

Tak, wyobrażam sobie ... Nie używam Scala, ale pochodzę z C# strony Świat i generics języka Java czują się jak za mało butów. –

5

Kiedy myśli zaakceptować A<T> ewentualnego typu T, ale nie potrzebują T, to jest prawidłowo wyrażone za pomocą wieloznacznych i pisanie A<?>. Spowoduje to pozbyć się ostrzeżenia w kodzie:

public void processA(A<?> a) { 
    Map<Integer, String> map = a.getMap(); 
} 

Korzystanie z gołą typ A nie jest traktowane równoważnie. Jak wyjaśniono w Java Language Specification, surowe typy podobne, które nie są przeznaczone do wykorzystania w nowym kodem:

Nieograniczony konwersji jest używany, aby umożliwić sprawne współdziałanie starszych kod, napisany przed wprowadzeniem typów generycznych, z bibliotek przeszły konwersję, aby użyć generyczności (proces, który nazywamy generacją). W takich okolicznościach (przede wszystkim klienci kolekcji zbiorów w java.util), starsze kody używają typów surowych (np. Kolekcja zamiast kolekcji <String>). Wyrażenia typów surowych są przekazywane jako argumenty metod bibliotecznych, które używają sparametryzowanych wersji tych samych typów, co typy odpowiadających im parametrów formalnych.

Nie można wykazać, że takie połączenia nie są statycznie bezpieczne w systemie typu przy użyciu generycznych. Odrzucenie takich wywołań spowoduje unieważnienie dużych ciał istniejącego kodu i uniemożliwi korzystanie z nowszych wersji bibliotek. To z kolei zniechęciłoby sprzedawców bibliotek do korzystania z generyczności. Aby zapobiec tak niepożądanemu zwrotowi zdarzeń, typ surowy może zostać przekonwertowany na dowolne wywołanie generycznej deklaracji typu, do którego odnosi się typ surowy. Choć konwersja jest niesłuszna, jest tolerowana jako ustępstwo na rzecz praktyczności. W takich przypadkach wydawane jest niezaznaczone ostrzeżenie.

Powiązane problemy