Co to jest Java w null?

252

Co to jest null?

Czy nulljest na przykład coś?

Do jakiego zestawu nullnależy?

Jak jest reprezentowany w pamięci?

unj2
źródło
yegor256. O wartości null z JLS. „Literał zerowy. Typ zerowy ma jedną wartość, odwołanie zerowe, reprezentowane przez literał zerowy zerowy, który jest utworzony ze znaków ASCII. Literał zerowy jest zawsze typu zerowego.” O punktach w artykule. „Zmienne i niekompletne obiekty” to funkcja. „Powolne awarie” to zdolność z założenia. „Myślenie komputerowe a myślenie obiektowe” to tylko dwa sposoby myślenia. „Dwuznaczny semantyczny” jest zbyt subiektywny. „Ad-hoc Error Handling” to kolejny rodzaj pracy z błędami. Null jest dosłowne lub cokolwiek innego określonego w JLS w przeciwieństwie do bycia dobrym lub złym.
Oleksii Kyslytsyn

Odpowiedzi:

310

Czy null jest czymkolwiek?

Nie, nie ma typu, który nullbyłby instanceof.

15.20.2 Operator porównania typów instanceof

RelationalExpression:
    RelationalExpression instanceof ReferenceType

W czasie wykonywania wynikiem działania instanceofoperatora jest to, trueczy wartość RelationalExpression nie jest, nulla odwołanie może być rzutowane na ReferenceType bez podnoszenia a ClassCastException. W przeciwnym razie wynikiem jest false.

Oznacza to, że dla każdego typu Ei Rdla dowolnego E o, gdzie o == null, o instanceof Rjest zawsze false.


Do jakiego zestawu należy „null”?

JLS 4.1 Rodzaje typów i wartości

Istnieje również specjalny typ zerowy , typ wyrażenia null, które nie ma nazwy. Ponieważ typ zerowy nie ma nazwy, nie można zadeklarować zmiennej typu zerowego ani rzutować na typ zerowy . nullOdniesienia jest jedyną możliwą wartość wyrazem zerowym typu. nullOdniesienia zawsze można rzucić na każdego rodzaju odniesienia. W praktyce programiści mogą zignorować typ zerowy i udawać, że nulljest to po prostu specjalny literał, który może być dowolnego typu odniesienia.


Co to jest null?

Jak mówi powyższy cytat JLS, w praktyce możesz po prostu udawać, że to „zwykły literał, który może być dowolnego rodzaju odniesienia”.

W Javie null == null(nie zawsze tak jest w innych językach). Należy również pamiętać, że zgodnie z umową ma również tę specjalną właściwość (z java.lang.Object):

public boolean equals(Object obj)

Dla każdego nieprzestrzegania nullwartości referencyjnej x, x.equals(null)powinien return false.

Jest to również wartość domyślna (dla zmiennych, które je mają) dla wszystkich typów referencji:

JLS 4.12.5 Początkowe wartości zmiennych

  • Każda zmienna klasy, zmienna instancji lub komponent tablicowy jest inicjowany z wartością domyślną podczas tworzenia:
    • Dla wszystkich typów referencyjnych wartością domyślną jest null.

Jak to jest używane, różni się. Możesz go użyć, aby włączyć tak zwaną leniwą inicjalizację pól, w której pole miałoby swoją wartość początkową do nullmomentu, aż faktycznie zostanie użyte, gdzie zostanie zastąpione wartością „rzeczywistą” (której obliczenie może być kosztowne).

Istnieją również inne zastosowania. Weźmy prawdziwy przykład z java.lang.System:

public static Console console()

Zwraca : konsola systemowa, jeśli istnieje, w przeciwnym razie null.

Jest to bardzo powszechny wzorzec użycia: nullsłuży do oznaczenia nieistnienia obiektu.

Oto inny przykład użycia, tym razem z java.io.BufferedReader:

public String readLine() throws IOException

Zwraca : A Stringzawierające zawartość wiersza, bez znaków zakończenia linii lub nulljeśli osiągnięto koniec strumienia.

Tak więc tutaj readLine()wróciłbym instanceof Stringdla każdej linii, aż w końcu zwraca a, nulloznaczające koniec. Umożliwia to przetwarzanie każdej linii w następujący sposób:

String line;
while ((line = reader.readLine()) != null) {
   process(line);
}

Interfejs API można zaprojektować tak, aby warunek zakończenia nie zależał od readLine()zwrotu null, ale widać, że ten projekt ma tę zaletę, że zwięzłość. Zauważ, że nie ma problemu z pustymi liniami, ponieważ pusta linia "" != null.

Weźmy inny przykład, tym razem z java.util.Map<K,V>:

V get(Object key)

Zwraca wartość, na którą jest mapowany określony klucz lub nulljeśli ta mapa nie zawiera mapowania dla klucza.

Jeśli ta mapa dopuszcza nullwartości, wówczas zwracana wartość nullniekoniecznie oznacza, że ​​mapa nie zawiera mapowania dla klucza; możliwe jest również, że mapa jawnie odwzorowuje klucz null. containsKeyOperacja może być używany do rozróżnienia tych dwóch przypadkach.

Tutaj zaczynamy widzieć, jak używanie nullmoże komplikować rzeczy. Pierwsze stwierdzenie mówi, że jeśli klucz nie jest zmapowany, nulljest zwracany. Drugie stwierdzenie mówi, że nawet jeśli klucz jest zmapowany, nullmożna go również zwrócić.

W przeciwieństwie do tego, java.util.Hashtableupraszcza rzeczy, nie dopuszczając nullkluczy i wartości; jego V get(Object key), jeśli zwraca null, jednoznacznie oznacza, że ​​klucz nie jest mapowany.

Możesz przeczytać resztę interfejsów API i dowiedzieć się, gdzie i jak nulljest używany. Pamiętaj, że nie zawsze są to przykłady najlepszych praktyk .

Ogólnie rzecz biorąc, nullsą używane jako specjalna wartość oznaczająca:

  • Stan niezainicjowany
  • Warunki zakończenia
  • Nieistniejący obiekt
  • Nieznana wartość

Jak jest reprezentowany w pamięci?

W Javie? Żaden z twoich problemów. I najlepiej tak zachować.


Czy nullto dobrze?

To jest teraz subiektywne. Niektórzy twierdzą, że nullpowoduje to wiele błędów programisty, których można było uniknąć. Niektórzy twierdzą, że w języku, który łapie NullPointerExceptionjak Java, dobrze jest go używać, ponieważ szybko zawiedziesz przy błędach programisty. Niektóre osoby unikają null, używając wzorca obiektu zerowego itp.

Sam w sobie jest to ogromny temat, dlatego najlepiej omówić go jako odpowiedź na inne pytanie.

Kończę ten z cytatem z wynalazca nullsiebie CAR Hoare (od Quicksort sławy):

Nazywam to moim błędem za miliard dolarów. To był wynalazek nullreferencji w 1965 roku. W tym czasie projektowałem pierwszy kompleksowy system typów dla referencji w języku obiektowym (ALGOL W). Moim celem było upewnienie się, że każde użycie referencji powinno być całkowicie bezpieczne, a sprawdzanie wykonywane automatycznie przez kompilator. Ale nie mogłem oprzeć się pokusie umieszczenia nullreferencji, po prostu dlatego, że tak łatwo ją wdrożyć. Doprowadziło to do niezliczonych błędów, podatności i awarii systemu, które prawdopodobnie spowodowały miliard dolarów bólu i szkód w ciągu ostatnich czterdziestu lat.

Wideo z tej prezentacji sięga głębiej; to zalecany zegarek.

środki smarujące wielotlenowe
źródło
4
Odwołania zerowe istniały w LISP (as NIL) w 1960 r. I prawdopodobnie wcześniej. Ale nie sądzę, żeby Hoare naprawdę starał się wymyślić wynalazek o zerowych referencjach w tym cytacie.
Stephen C,
7
Hoare nie próbuje zastrzegać wynalazku zerowych referencji; twierdzi jedynie, że udostępnił je w szczególnie wpływowym miejscu. Istnieje wiele języków, w tym Java, które wyraźnie czerpały inspirację z Algolu, a jeśli ich użycie zerowych referencji było nawet częściowo inspirowane lub kopiowane z Algolu, Hoare słusznie przyjmuje na siebie część winy za ich koszty. Wydaje mi się jednak, że jego ocena jest raczej niska. Bilion dolarów może być bliższy prawdziwemu kosztowi.
cjs
32

Czy null jest czymkolwiek?

Nie. Dlatego null instanceof Xwróci falsedo wszystkich klas X. (Nie daj się zwieść faktowi, że można przypisać nulldo zmiennej, której typ jest typem obiektu. Ściśle mówiąc, przypisanie obejmuje niejawną konwersję typu; patrz poniżej.)

Do jakiego zestawu należy „null”?

Jest to jedyny element typu null, w którym typ null jest zdefiniowany w następujący sposób:

„Istnieje również specjalny typ zerowy, typ wyrażenia null, który nie ma nazwy. Ponieważ typ null nie ma nazwy, nie można zadeklarować zmiennej typu null ani rzutować na typ null. Null referencja jest jedyną możliwą wartością wyrażenia typu null. Referencja null może być zawsze rzutowana na dowolny typ referencji. W praktyce programista może zignorować typ null i udawać, że null jest jedynie specjalnym dosłownym, który może być dowolnego typ odniesienia ”. JLS 4.1

Co to jest null?

Patrz wyżej. W niektórych kontekstach nulljest używany do oznaczenia „brak obiektu” lub „nieznany” lub „niedostępny”, ale te znaczenia są specyficzne dla aplikacji.

Jak jest reprezentowany w pamięci?

Jest to specyficzne dla implementacji i nie będzie można zobaczyć reprezentacji nullw czystym programie Java. (Ale nulljest reprezentowany jako zerowy adres / wskaźnik komputera w większości, jeśli nie we wszystkich implementacjach Java).

Stephen C.
źródło
14

Co to jest null?

To nic nie znaczy.

Czy null jest czymkolwiek?

Nie, ponieważ jest niczym. To nie może być żadna instancja.

Do jakiego zestawu należy null?

Żadnego zestawu

Jak jest reprezentowany w pamięci?

Jeśli niektóre odniesienia wskazują na to:

Object o=new Object();

W pamięci sterty część miejsca przypisana do nowo utworzonego obiektu. I o wskaże na to przydzielone miejsce w pamięci.

Teraz o=null;

Oznacza to, że teraz o nie będzie wskazywać na tę przestrzeń pamięci obiektu.

Sanjay Jain
źródło
1
„Teraz o = null; Oznacza to, że teraz o nie będzie wskazywać na tę przestrzeń pamięci obiektu.” Myślę, że tak działa Garbage Collection w JAVA
Hardik Mishra,
9

Nie, to nie jest żadna instancja, instanceof zawsze będzie fałszywy.

Tomek
źródło
7

Słowo kluczowe null jest literałem reprezentującym odwołanie null, które nie odwołuje się do żadnego obiektu . null jest domyślną wartością zmiennych typu referencyjnego.

Może także rzucić okiem

null: Glosariusz Java

Adriaan Stander
źródło
2
To nie jest słowo kluczowe, to dosłowne . Niska jakość i nienormatywne cytowanie.
Markiz Lorne
6

Null nie jest instancją żadnej klasy.

Można jednak przypisać null do zmiennych dowolnego typu (obiekt lub tablica):

 // this is false   
 boolean nope = (null instanceof String);

 // but you can still use it as a String
 String x = null;
 "abc".startsWith(null);
Thilo
źródło
6

Null in Java (tm)

W C i C ++ „NULL” jest stałą zdefiniowaną w pliku nagłówkowym o wartości takiej jak:

    0

lub:

    0L

lub:

    ((void*)0)

w zależności od kompilatora i opcji modelu pamięci. NULL, ściśle mówiąc, nie jest częścią samego C / C ++.

W Javie (tm) „null” nie jest słowem kluczowym, lecz specjalnym literałem typu null. Może być rzutowany na dowolny typ odwołania, ale nie na dowolny typ pierwotny, taki jak int lub boolean. Literał zerowy niekoniecznie ma wartość zero. Nie można rzutować na typ zerowy ani zadeklarować zmiennej tego typu.

s. 27
źródło
5

Reprezentacja kodu bajtowego

Java nullma bezpośrednią obsługę JVM: do jego implementacji wykorzystywane są trzy instrukcje:

  • aconst_null: np. aby ustawić zmienną na nulljak wObject o = null;
  • ifnulloraz ifnonnull: np. w celu porównania obiektu nulljak wif (o == null)

Rozdział 6 „Zestaw instrukcji wirtualnej maszyny Java” następnie wspomina o wpływie nullinnych instrukcji: rzuca NullPointerExceptiondla wielu z nich.

2.4 „Typy referencyjne i wartości” również wspominają nullogólnie:

Wartość referencyjna może być również specjalną referencją zerową, referencją do żadnego obiektu, która będzie tutaj oznaczona null. Odwołanie zerowe początkowo nie ma typu czasu wykonywania, ale może być rzutowane na dowolny typ. Domyślna wartość typu odwołania to null.

Ciro Santilli
źródło
4

nullma szczególną wartość, nie jest to przypadek niczego. Z oczywistych względów nie może to być instanceofnic.

fastcodejava
źródło
3

nullto specjalna wartość, która nie jest instancją żadnej klasy. Ilustruje to następujący program:

public class X {
   void f(Object o)
   { 
      System.out.println(o instanceof String);   // Output is "false"
   }
   public static void main(String[] args) {
      new X().f(null);
   }
}
Itay Maman
źródło
6
Jedyną rzeczą, którą pokazuje przykład, jest to, że nullnie jest to instancja String.
Sasha Chedygov
4
Gdybyś zmienił podpis na void f(String o), miałoby to większy sens.
Thilo,
2

null w Javie jest podobny / podobny do nullptr w C ++.

Program w C ++:

class Point
{
    private:
       int x;
       int y;
    public:
       Point(int ix, int iy)
       {
           x = ix;
           y = iy;
       }
       void print() { std::cout << '(' << x << ',' << y << ')'; }
};
int main()
{
    Point* p = new Point(3,5);
    if (p != nullptr)
    {
       p->print();
       p = nullptr;
    }
    else
    {
        std::cout << "p is null" << std::endl;
    }
    return 0;
}

Ten sam program w Javie:

public class Point {
    private int x;
    private int y;
    public Point(int ix, int iy) {
        x = ix;
        y = iy;
    }
    public void print() { System.out.print("(" + x + "," + y + ")"); }
}
class Program
{
    public static void main(String[] args) {
        Point p = new Point(3,5);
        if (p != null)
        {
            p.print();
            p = null;
        }
        else
        {
            System.out.println("p is null");
        }
    }
}

Czy rozumiesz teraz na podstawie kodów powyżej, co jest puste w Javie? Jeśli nie, to polecam nauczyć się wskaźników w C / C ++, a wtedy zrozumiesz.

Zauważ, że w C, w przeciwieństwie do C ++, nullptr jest niezdefiniowany, ale zamiast niego używany jest NULL, który może być również używany w C ++, ale w C ++ nullptr jest bardziej preferowany niż tylko NULL, ponieważ NULL w C jest zawsze powiązany ze wskaźnikami i to jest tak, więc w C ++ przyrostek „ptr” został dołączony na końcu słowa, a także wszystkie litery są teraz małe, ale jest to mniej ważne.

W Javie każda zmienna nietypowej klasy typu jest zawsze odniesieniem do obiektu tego typu lub odziedziczonej, a null jest odwołaniem do obiektu klasy zerowej, ale nie wskaźnikiem zerowym, ponieważ w Javie nie ma czegoś takiego jak „wskaźnik”, ale odniesienia do klasy obiekty są używane zamiast tego, a null w Javie jest powiązany z odwołaniami do obiektów klasy, więc można go również nazwać „nullref” lub „nullrefobj”, ale jest on długi, więc po prostu nazwij go „null”.

W C ++ możesz używać wskaźników i wartości nullptr dla opcjonalnych elementów / zmiennych, tj. Element / zmienna, która nie ma żadnej wartości, a jeśli nie ma żadnej wartości, to jest równa nullptr, więc jak na przykład można użyć wartości null w Javie.


źródło
1

W Javie istnieją dwie główne kategorie typów: prymitywne i referencyjne . Zmienne zadeklarowane z wartości podstawowych w magazynie typu; zmienne zadeklarowane z odniesieniami do magazynu typu odniesienia.

String x = null;

W takim przypadku instrukcja inicjalizacji deklaruje zmienne „x”. „X” przechowuje odwołanie do ciągu. Tutaj jest zero . Po pierwsze, null nie jest prawidłową instancją obiektu, więc nie ma dla niej przydzielonej pamięci. Jest to po prostu wartość wskazująca, że ​​odwołanie do obiektu nie odnosi się obecnie do obiektu.

Anand
źródło
0

Interesującym sposobem, aby zobaczyć wartość null w java jest, moim zdaniem, postrzeganie jej jako czegoś, co NIE oznacza braku informacji, ale po prostu jako dosłowną wartość, którą można przypisać do odwołania dowolnego typu. Jeśli pomyślisz o tym, jeśli oznaczało to brak informacji, to prawda, że ​​a1 == a2 jest prawdziwa, nie ma sensu (w przypadku, gdy obaj mieli przypisaną wartość null), ponieważ mogliby naprawdę wskazywać na DOWOLNY obiekt (po prostu nie wiem na jakie obiekty powinny wskazywać) ... Nawiasem mówiąc, null == null zwraca true w Javie. Gdyby java np. Byłaby jak SQL: 1999, to null == null zwróciłoby nieznane (wartość logiczna w SQL: 1999 może przyjąć trzy wartości: prawda, fałsz i nieznana, ale w praktyce nieznana jest implementowana jako null w prawdziwych systemach) ... http://en.wikipedia.org/wiki/SQL

Bat0u89
źródło
0

Krótka i precyzyjna odpowiedź, która formalnie odpowiada na wszystkie pytania z JLS:

3.10.7 Null dosłowny

Typ zerowy ma jedną wartość, odwołanie zerowe, reprezentowane przez literał zerowy zerowy, który jest utworzony ze znaków ASCII.

Literał zerowy jest zawsze typu zerowego.

Przydzielane jest tylko odwołanie typu, które jest przypisane do null. Nie przypisujesz żadnej wartości (obiektu) do odwołania. Taki przydział jest specyficzny dla JVM, ile zajmie odniesienie i w którym obszarze pamięci zostanie przydzielony.

Oleksii Kyslytsyn
źródło