Что такое нуль в Java?


252

Что такое null?

Это nullпример чего-либо?

К какому набору nullотносится?

Как это представлено в памяти?


yegor256. О нуле из JLS. «Нулевой литерал. Нулевой тип имеет одно значение - нулевую ссылку, представленную нулевым литералом null, который сформирован из символов ASCII. Нулевой литерал всегда имеет нулевой тип». О пунктах в статье. «Изменяемые и неполные объекты» - это функция. «Slow Failing» - это способность по замыслу. «Компьютерное мышление против объектного мышления» - это всего лишь два способа мышления. «Двусмысленная семантика» слишком субъективна. «Специальная обработка ошибок» - еще один тип работы с ошибками. Нуль - это литерал или что-то еще, указанное в JLS, в отличие от того, что он плохой или хороший.
Алексей Кислицын

Ответы:


310

Является ли null экземпляром чего-либо?

Нет, нет типа, который nullявляется instanceof.

15.20.2 Оператор сравнения типов instanceof

RelationalExpression:
    RelationalExpression instanceof ReferenceType

Во время выполнения результатом instanceofоператора является то, что trueесли значение RelationalExpression отсутствует, nullи ссылка может быть приведена к ReferenceType без вызова a ClassCastException. В противном случае результат false.

Это означает, что для любого типа Eи Rдля любого E o, где o == null, o instanceof Rвсегда false.


К какому набору принадлежит «ноль»?

JLS 4.1 Виды типов и значений

Существует также специальный нулевой тип, тип выражения null, который не имеет имени. Поскольку нулевой тип не имеет имени, невозможно объявить переменную нулевого типа или привести к нулевому типу. nullЗадание является единственно возможным значением выражения нулевого типа. nullСсылка всегда может быть приведена к любому ссылочного типа. На практике программист может игнорировать нулевой тип и просто делать вид, что nullэто просто специальный литерал, который может иметь любой ссылочный тип.


Что такое ноль?

Как сказано в приведенной выше цитате JLS, на практике вы можете просто притвориться, что это «просто специальный литерал, который может иметь любой ссылочный тип».

В Java null == null(это не всегда так в других языках). Также обратите внимание, что по контракту оно также имеет это специальное свойство (from java.lang.Object):

public boolean equals(Object obj)

Для любого не nullэталонного значения x, x.equals(null)следует return false.

Это также значение по умолчанию (для переменных, у которых они есть) для всех ссылочных типов:

JLS 4.12.5 Начальные значения переменных

  • Каждая переменная класса, переменная экземпляра или компонент массива инициализируется значением по умолчанию при создании:
    • Для всех ссылочных типов значением по умолчанию является null.

Как это используется, варьируется. Вы можете использовать его, чтобы включить так называемую ленивую инициализацию полей, где поле будет иметь свое начальное значение nullдо момента его фактического использования, где оно будет заменено «реальным» значением (которое может быть дорогим для вычисления).

Есть и другие варианты использования. Давайте возьмем реальный пример из java.lang.System:

public static Console console()

Возвращает : Системная консоль, если есть, в противном случае null.

Это очень распространенный шаблон использования: nullиспользуется для обозначения несуществования объекта.

Вот еще один пример использования, на этот раз из java.io.BufferedReader:

public String readLine() throws IOException

Возвраты : A, Stringсодержащий содержимое строки, не включая символы окончания строки, или nullесли достигнут конец потока.

Так что здесь, readLine()будет возвращаться instanceof Stringдля каждой строки, пока он, наконец, не вернет a, nullчтобы обозначить конец. Это позволяет обрабатывать каждую строку следующим образом:

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

Можно спроектировать API так, чтобы условие завершения не зависело от readLine()возврата null, но можно увидеть, что этот дизайн имеет преимущество, заключающееся в том, чтобы сделать вещи краткими. Обратите внимание, что нет проблем с пустыми строками, потому что пустая строка "" != null.

Давайте возьмем другой пример, на этот раз из java.util.Map<K,V>:

V get(Object key)

Возвращает значение, которому сопоставлен указанный ключ, или nullесли эта карта не содержит сопоставления для ключа.

Если эта карта допускает nullзначения, то возвращаемое значение nullне обязательно указывает, что карта не содержит сопоставления для ключа; также возможно, что карта явно отображает ключ null. containsKeyОперация может быть использована , чтобы отличить эти два случая.

Здесь мы начинаем видеть, как использование nullможет усложнить ситуацию. Первое утверждение говорит, что если ключ не сопоставлен, nullвозвращается. Второе утверждение говорит о том, что даже если ключ сопоставлен, nullего также можно вернуть.

Напротив, java.util.Hashtableделает вещи проще, не разрешая nullключи и значения; его V get(Object key), если возвращается null, однозначно означает, что ключ не сопоставлен.

Вы можете прочитать остальные API и найти, где и как nullиспользуется. Имейте в виду, что они не всегда лучшие примеры практики .

Вообще говоря, nullиспользуются как специальные значения для обозначения:

  • Неинициализированное состояние
  • Условие прекращения
  • Несуществующий объект
  • Неизвестная ценность

Как это представлено в памяти?

На яве? Не твоя забота. И лучше всего так держать.


Это nullхорошая вещь?

Это сейчас пограничный субъективный. Некоторые люди говорят, что это nullвызывает много ошибок программиста, которых можно было бы избежать. Некоторые говорят, что на языке, который ловит NullPointerExceptionкак Java, хорошо использовать его, потому что вы будете быстро отказывать в ошибках программиста. Некоторые люди избегают nullиспользования шаблона объекта Null и т. Д.

Это огромная тема сама по себе, поэтому ее лучше обсуждать как ответ на другой вопрос.

Я закончу это цитатой из изобретателя самого nullсебя, CAR Hoare (быстрой славы):

Я называю это моей ошибкой в ​​миллиард долларов. Это было изобретение nullссылки в 1965 году. В то время я разрабатывал первую комплексную систему типов для ссылок на объектно-ориентированном языке (ALGOL W). Моя цель состояла в том, чтобы гарантировать, что любое использование ссылок должно быть абсолютно безопасным, с проверкой, выполняемой автоматически компилятором. Но я не мог удержаться от соблазна вставить nullссылку просто потому, что это было легко реализовать. Это привело к бесчисленным ошибкам, уязвимостям и сбоям системы, которые, вероятно, причинили миллиард долларов боли и ущерба за последние сорок лет.

Видео этой презентации идет глубже; это рекомендуемые часы.


5
Нулевые ссылки существовали в LISP (as NIL) в 1960 году, а возможно и раньше. Но я не думаю, что Хоар действительно пытается претендовать на изобретение пустых ссылок в этой цитате.
Стивен С.

7
Хоар не пытается выдумать изобретение нулевых ссылок; он просто утверждает, что сделал их доступными в особенно влиятельном месте. Есть много языков, включая Java, которые явно черпали вдохновение у Алгола, и если их использование нулевых ссылок было даже частично вдохновлено или скопировано с Алгола, Хоар прав, принимая на себя часть ответственности за их стоимость. Однако я чувствую, что его оценка довольно низкая. Триллион долларов может быть ближе к реальной стоимости.
CJS

32

Является ли null экземпляром чего-либо?

Нет. Поэтому null instanceof Xвернусь falseна все занятия X. (Не обманывайте себя тем фактом, что вы можете присваивать nullпеременную, тип которой является типом объекта. Строго говоря, присваивание включает в себя неявное преобразование типа; см. Ниже.)

К какому набору принадлежит «ноль»?

Это единственный элемент нулевого типа, где нулевой тип определяется следующим образом:

"Существует также специальный нулевой тип, тип выражения null, у которого нет имени. Поскольку нулевой тип не имеет имени, невозможно объявить переменную нулевого типа или привести к нулевому типу. ссылка - это единственно возможное значение выражения нулевого типа. Нулевая ссылка всегда может быть приведена к любому ссылочному типу. На практике программист может игнорировать нулевой тип и просто делать вид, что ноль - это просто специальный литерал, который может иметь любой ссылочный тип. " JLS 4.1

Что такое ноль?

Смотри выше. В некоторых контекстах nullиспользуется для обозначения «нет объекта», «неизвестен» или «недоступен», но эти значения зависят от конкретного приложения.

Как это представлено в памяти?

Это зависит от реализации, и вы не сможете увидеть представление nullв чистой Java-программе. (Но nullпредставлен как нулевой машинный адрес / указатель в большинстве, если не во всех реализациях Java.)


14

Что такое ноль?

Это ничего.

Является ли null экземпляром чего-либо?

Нет, поскольку это ничто. Это не может быть примером чего-либо.

К какому набору принадлежит нуль?

Нет любого набора

Как это представлено в памяти?

Если некоторые ссылки указывают на это, как:

Object o=new Object();

В куче памяти выделено место для нового созданного объекта. И о будет указывать на это назначенное место в памяти.

Сейчас o=null;

Это означает, что теперь o не будет указывать на это пространство памяти объекта.


1
«Теперь o = null; это означает, что теперь o не будет указывать на это пространство памяти объекта». Я думаю, что так работает
сборка

9

Нет, это не экземпляр чего-либо, instanceof всегда будет ложным.


7

Ключевое слово null - это литерал, представляющий нулевую ссылку, который не относится ни к какому объекту . null - это значение по умолчанию для переменных ссылочного типа.

Также возможно взглянуть на

null: Глоссарий Java


2
Это не ключевое слово, это буквальное . Низкое качество и ненормативная цитата.
Маркиз Лорн

6

Нуль не является экземпляром какого-либо класса.

Однако вы можете присвоить значение null переменным любого типа (объекта или массива):

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

 // but you can still use it as a String
 String x = null;
 "abc".startsWith(null);

6

Нуль в Java (тм)

В C и C ++ «NULL» - это константа, определенная в заголовочном файле, со значением, например:

    0

или:

    0L

или:

    ((void*)0)

в зависимости от параметров компилятора и модели памяти. Строго говоря, NULL не является частью самого C / C ++.

В Java (tm) «null» - это не ключевое слово, а специальный литерал типа null. Он может быть приведен к любому ссылочному типу, но не к любому примитивному типу, такому как int или boolean. Нулевой литерал не обязательно имеет значение ноль. И невозможно привести к нулевому типу или объявить переменную этого типа.


5

Представление байт-кода

Java nullимеет прямую поддержку JVM: для ее реализации используются три инструкции:

  • aconst_null: например, чтобы установить переменную nullкак вObject o = null;
  • ifnullи ifnonnull: например, чтобы сравнить объект nullкак вif (o == null)

Затем в главе 6 «Набор инструкций виртуальной машины Java» упоминается влияние nullдругих инструкций: NullPointerExceptionдля многих из них они выдаются.

2,4. «Типы ссылок и значения» также упоминаются nullв общих терминах:

Ссылочным значением также может быть специальная нулевая ссылка, ссылка на отсутствие объекта, которая будет обозначаться здесь нулевой. Нулевая ссылка изначально не имеет типа времени выполнения, но может быть приведена к любому типу. Значением по умолчанию для ссылочного типа является ноль.


4

nullэто особая ценность, это не экземпляр чего-либо. По понятной причине это не может быть instanceofничто.


3

nullэто специальное значение, которое не является экземпляром какого-либо класса. Это иллюстрируется следующей программой:

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);
   }
}

6
Единственное, что показывает пример, это то, что nullэто не экземпляр String.
Саша Чедыгов

4
Если вы измените подпись на void f(String o), это будет иметь больше смысла.
Тило

2

null в Java похож на / похож на nullptr в C ++.

Программа на 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;
}

Та же программа на Java:

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");
        }
    }
}

Теперь вы понимаете из приведенных выше кодов, что является нулевым в Java? Если нет, то я рекомендую вам изучить указатели на C / C ++, и тогда вы поймете.

Обратите внимание, что в C, в отличие от C ++, nullptr не определен, но вместо него используется NULL, что также можно использовать и в C ++, но в C ++ nullptr предпочтительнее, чем просто NULL, потому что NULL в C всегда связан с указателями, и это это так, поэтому в C ++ суффикс «ptr» был добавлен в конец слова, а также все буквы теперь строчные, но это менее важно.

В Java каждая переменная типа non-primitive класса всегда является ссылкой на объект этого типа или наследуется, и null является ссылкой на объект класса null, но не указателем null, потому что в Java нет такой вещи как «указатель», а ссылки на класс вместо этого используются объекты, и нуль в Java связан со ссылками на объекты класса, поэтому вы также можете называть его как «nullref» или «nullrefobj», но это долго, поэтому просто назовите его «null».

В C ++ вы можете использовать указатели и значение nullptr для необязательных членов / переменных, то есть члена / переменной, которая не имеет значения, а если она не имеет значения, то она равна nullptr, поэтому, например, можно использовать null в Java.


1

В Java есть две основные категории типов: примитивные и ссылочные . Переменные, объявленные для примитивного типа, хранят значения; переменные, объявленные из ссылочного типа, хранят ссылки.

String x = null;

В этом случае оператор инициализации объявляет переменную «x». «X» хранит ссылку на строку. Здесь ноль . Прежде всего, null не является допустимым экземпляром объекта, поэтому для него не выделена память. Это просто значение, которое указывает, что ссылка на объект в данный момент не ссылается на объект.


0

На мой взгляд, интересный способ увидеть ноль в Java - это то, что НЕ обозначает отсутствие информации, а просто как буквальное значение, которое может быть присвоено ссылке любого типа. Если вы думаете об этом, если оно обозначает отсутствие информации, то для a1 == a2 быть истинным не имеет смысла (в случае, если им обоим присвоено значение null), поскольку они действительно могут указывать на ЛЮБОЙ объект (мы просто не знаю, на какие объекты они должны указывать) ... кстати, null == null возвращает true в java. Если java, например, будет похож на SQL: 1999, тогда null == null вернет неизвестное (логическое значение в SQL: 1999 может принимать три значения: true, false и unknown, но на практике unknown реализовано как null в реальных системах) ... http://en.wikipedia.org/wiki/SQL


0

Краткий и точный ответ, который формально отвечает на все ваши вопросы от JLS:

3.10.7. Нулевой литерал

Нулевой тип имеет одно значение, нулевую ссылку, представленную нулевым литералом null, который сформирован из символов ASCII.

Нулевой литерал всегда имеет нулевой тип.

Выделяется только ссылка типа, который назначен на нуль. Вы не присваиваете значение (объект) для ссылки. Такое распределение зависит от JVM, сколько ссылки займет и в какой области памяти оно будет выделено.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.