Natknąłem się na zachowanie, o którym wcześniej nie wiedziałem, w kodzie śledzenia.Różnica w zachowaniu: "Null" inicjalizowany końcowy element statyczny i "null" inicjowana ostateczna zmienna lokalna
Rozważmy 1 st sprawy:
public static void main(String[] args) {
final String str = null;
System.out.println(str.length()); // Compiler Warning: NullPointerAccess
}
Zgodnie z oczekiwaniami, kompilator pokazuje mi następujące ostrzeżenie na str
będąc zerowy - Null dostęp wskazówka: Zmienna str może być tylko wartość null w tym Lokalizacja.
Teraz, kiedy przeszło zmienną static final pole inicjowane zerową:
class Demo {
static final String str = null;
public static void main(String[] args) {
System.out.println(str.length()); // No Compiler Warning
}
}
Teraz kompilator nie wykazuje żadnego ostrzeżenia. AFAIK, kompilator powinien wiedzieć, że str
jest ostateczny, nie zmieni jego wartości w żadnym miejscu kodu. A biorąc pod uwagę, że jest to null
, z pewnością wyniknie później NullPointerException
, co robi.
Mimo że kompilator skutecznie ostrzega mnie o tym w pierwszym przypadku, dlaczego nie może zidentyfikować tego w drugim przypadku. Dlaczego ta zmiana zachowania? Zachowanie jest takie samo, jeśli zmienię pole static
na instance
i uzyskam do niego dostęp za pomocą instancji Demo
.
Myślałem, że to zachowanie mogło zostać określone w JLS, więc przeszedłem przez temat Definite Assignment, ale nie znalazłem nic związanego z tym problemem. Czy ktoś może wyjaśnić zmianę zachowania? Szukam jakiegoś mocnego punktu z jakimś łączem do JLS, jeśli to możliwe?
Oprócz, że dlaczego kompilator pokazuje mi tylko ostrzeżenie w pierwszej kolejności, jak myślę, że z tego samego powodu ja podanej powyżej, metoda wywołanie pewnością rzucać NPE w czasie wykonywania, ponieważ pole może” t być zmienione? Dlaczego nie wyświetlił mi się błąd kompilatora? Czy oczekuję zbyt wiele od kompilatora, ponieważ wydaje się dość oczywiste, że wynik runtime w postaci str.length()
nie może być równy NPE
?
Niestety dla brakujących że wcześniej:
Używam Eclipse Juno na Ubuntu 12.04 z OpenJDK 7.
JLS nie * zwykle * zagłębia się w szczegóły ostrzeżeń - jest to szczegół implementacji kompilatora, nie byłbym zaskoczony, gdyby niektóre kompilatory * ostrzeżenia * o tym ostrzeżono: –
@JonSkeet. każdy kompilator zachowuje się w taki sam sposób w obu przypadkach.W obu przypadkach uzyskuję dostęp do metody na określonym zerowym odwołaniu –
Tak, byłoby miło to zrobić - ale mówię, że to kwestia Daleko idą implementacje kompilatora, nie oczekiwałbym, że będzie w JLS, a ty nie powiesz, który kompilator używasz, –