Pola statyczne w zerowym odwołaniu w Javie


119

staticelementy członkowskie ( staticpola lub staticmetody) w Javie są skojarzone z odpowiednimi klasami, a nie z obiektami tej klasy. Poniższy kod próbuje uzyskać dostęp do pola statycznego w nullodwołaniu.

public class Main
{
    private static final int value = 10;

    public Main getNull()
    {
        return null;
    }

    public static void main(String[] args)
    {
        Main main=new Main();
        System.out.println("value = "+main.getNull().value);
    }
}

Chociaż main.getNull()zwraca null, działa i wyświetla value = 10. Jak działa ten kod?



4
Dla zabawy spróbuj Main main = null; main.getNull().value.
Marko Topolnik

1
To przypomina mi, new Thread[]{}[-1].sleep(10);gdzie sleep () jest metodą statyczną. Kiedyś działało to pomyślnie w niektórych starszych wersjach Java.
hertzsprung

Odpowiedzi:


93

To zachowanie jest określone w specyfikacji języka Java :

odwołanie o wartości null może służyć do uzyskiwania dostępu do zmiennej klasowej (statycznej) bez powodowania wyjątku.

Bardziej szczegółowo, statyczna ocena pola , na przykład Primary.staticFielddziała w następujący sposób (wyróżnienie moje) - w Twoim przypadku Primary = main.getNull():

  • Wyrażenie podstawowe jest oceniane, a wynik jest odrzucany . […]
  • Jeśli pole nie jest pustym polem końcowym, wynikiem jest wartość określonej zmiennej klasy w klasie lub interfejsie, który jest typem wyrażenia Primary. […]

5
Jeśli ktoś ma jakieś informacje o tym, dlaczego dokonano takiego wyboru, byłoby to interesujące.

6
@JonofAllTrades Myślę, że to oczywiste: rozsądne jest, aby nie zgłaszać żadnych wyjątków podczas wywoływania odwołania o wartości null, ponieważ nie ma to znaczenia, ponieważ metoda jest statyczna.
Malcolm,

13
@JonofAllTrades: prawdziwe pytanie brzmi: dlaczego wybrano zezwolenie na wywoływanie elementów statycznych jako instancji ... Wydaje mi się, że prowadzi to tylko do nieporozumień i mniej czytelnego kodu.
Falanwe

2
@Falanwe: Zgoda i jest to konstrukcja, której nie potrzebowałem, chociaż pracuję głównie w .NET, gdzie nie jest to dozwolone. Wydaje mi się, że możesz chcieć wywołać odpowiednią statyczną metodę podklasy, gdy otrzymasz odwołanie do klasy nadrzędnej.

8
@Falanwe Jest to dozwolone, ale powoduje ostrzeżenie w Eclipse: „Do statycznego pola Main.value należy uzyskać dostęp w sposób statyczny”. Przynajmniej ci z nas, którzy są wybredni w kwestii ostrzeżeń (jak ja), unikną takiego kodu.
Artem

19

Ponieważ, jak powiedziałeś, pola statyczne nie są powiązane z instancją.

Możliwość dostępu do pól statycznych z odwołania do instancji (tak jak to robisz) jest jedynie cukrem syntaktycznym i nie ma dodatkowego znaczenia.
Twój kod kompiluje się do

main.getNull(); 
Main.value

7
Nazwałbym to cukrem syntaktycznym, bardziej jak syntaktyczne trociny;)
Stephen Swensen

3

Kiedykolwiek uzyskujesz dostęp do zmiennej statycznej lub metody z obiektami w czasie kompilacji, jest ona konwertowana na nazwę klasy. na przykład:

Main main = null;
System.out.println(main.value);

Wyświetli wartość zmiennej statycznej, ponieważ w czasie kompilacji zostanie przekonwertowana na

System.out.println(Main.value);

Dowód:

pobierz dekompilator i Zdekompiluj swój plik .class do pliku .java, a zobaczysz, że wszystkie metody statyczne lub zmienna nazwa obiektu jest automatycznie zastępowana nazwą klasy.


3
  1. Dostęp do staticelementu członkowskiego z nazwą klasy jest dozwolony, ale nie napisano, że nie można uzyskać dostępu do staticelementu członkowskiego za pomocą zmiennej odwołania do obiektu. Więc to działa tutaj.

  2. nullZmienna odwołanie do obiektu może uzyskać dostęp do staticzmiennej klasy nie rzucając wyjątek albo w czasie kompilacji i czasie wykonywania.


2

Zmienna statyczna i metoda zawsze należą do klasy. Więc kiedy kiedykolwiek tworzymy dowolny obiekt, tylko zmienna niestatyczna i metody idą na stos wraz z obiektem, ale statyczne rezyduje w obszarze metod z klasą. Dlatego kiedykolwiek próbujemy uzyskać dostęp do zmiennej statycznej lub metody, jest ona konwertowana na zmienną kropkową nazwę klasy lub nazwę metody.

Więcej informacji można znaleźć w poniższym linku.

http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.