В чем разница между неинициализированной переменной объекта и переменной объекта, инициализированной нулем в Java

12

У меня есть следующие две объектные переменные

Date a;
Date b=null;

Определенно и «a», и «b» не относятся ни к каким объектам.

Теперь, если я призываю следующее утверждение

System.out.println(a.toString());

Там будет ошибка времени компиляции, тогда как, если я вызову следующее утверждение

System.out.println(b.toString());

Не будет ошибки времени компиляции, но будет ошибка времени выполнения. В чем причина этого, и какое значение будет фактически сохранено в 'b', чтобы представить нулевое значение?

Harish_N
источник
2
спрашивал и отвечал много раз в SO: почему локальные переменные не инициализируются в Java? , Неинициализированные переменные и члены в Java и во многих связанных с ними вопросах
gnat
@gnat, другие вопросы касаются разницы между «неинициализированным» и «нулевым»? Тот факт, что ответ похож, не означает, что это дублирующий вопрос.
DougM
@ ДаугМ, конечно, ты прочитал первый вопрос, который я упомянул? «Была ли какая-то причина, по которой разработчики Java считали, что локальным переменным не следует давать значение по умолчанию? Серьезно, если переменным экземпляра можно дать значение по умолчанию, то почему мы не можем сделать то же самое для локальных переменных?» (FWIW технически это не может быть дубликатом, просто потому что это на другом сайте)
gnat
1
Это не учитывает разницу между «неинициализированными» и «инициализированными как нулевые», только «почему переменные автоматически не инициализируются как нулевые?» Та же тема, немного другой вопрос.
DougM

Ответы:

3

Это потому, что состояние локальных переменных контролируется в рамках своей области

 // method/loop/if/try-catch etc...
 {
   Date d; // if it's not intialised in this scope then its not intialised  anywhere
 }

Что не так для полей

class Foo{
 Date d; // it could be intialised anywhere, so its out of control and java will set to null for you
}

Теперь, почему хорошо установить переменную в null и использовать ее немедленно? может быть, это историческая ошибка, которая иногда приводит к ужасным ошибкам

 {
  Date d = null;
  try{
  }catch{ // hide it here 
  }
  return d;
 } 

Теперь в чем семантическая разница?

Date d;

просто объявляет переменную, которая может содержать ссылку, которая указывает на объект типа Date, однако

Date d= null; 

делает то же самое, но ссылка на этот раз указывает на ноль, ноль, как и любая ссылка, занимает пространство собственного указателя, то есть 4 байта на 32-битных машинах и 8 байтов на 64-битных машинах

Сулейман Джнейди
источник
это, кажется, просто повторяет сказанное и объясненное в предыдущем ответе, опубликованном час назад
комнат
@gnat Спасибо за ваш комментарий, но я не думаю, что это, ура
Слейман Джнейди
Вы имеете в виду, что null также является объектом, хранящимся где-то в памяти, и все переменные объекта, назначенные с помощью null, указывают на этот нулевой объект.
Harish_N
@ Harish.N нет, я этого не говорил, я сказал, что это ссылка, а не объект
Слейман Джнейди,
В приведенном вами примере 'd' является ссылкой .. это ссылка на объект типа Date ... аналогично, если null является ссылкой .. на какой объект он ссылается ..?
Harish_N
19

Для полей классов нет никакой разницы. Они nullпо умолчанию для объектов, 0 для числовых значений и falseлогических значений.

Для переменных, объявленных в методах - Java требует их инициализации. Не инициализация их вызывает ошибку времени компиляции при обращении к ним.

В чем причина? Поля класса могут быть изменены любым методом. В любом порядке метод вызывается. Все не приватные поля могут быть изменены другими классами и / или классами, расширяющими этот класс. Следовательно, нет смысла уведомлять о неинициализированной переменной, поскольку она может быть назначена во многих местах.

Переменные внутри методов, однако, являются локальными и могут быть изменены только внутри самого метода. Следовательно, возможно и рационально указать возможные ошибки. И компилятор пытается это сделать. Если он знает, что поле не инициализировано, он покажет ошибку, потому что это никогда не то, что вы хотите. Если он не уверен - он выдаст предупреждение, чтобы вы могли убедиться.

public static class Test {
    Date a; // ok 
    Date b = null; // ok

    public void test() {
        Date c;
        Date d = null;

        System.out.println(a.toString());
        System.out.println(b.toString());
        System.out.println(c.toString()); // error
        System.out.println(d.toString()); // warning
    }
}
Дариуш
источник