Переменные в Java можно разделить на экземпляры, статические и локальные. В программировании всегда желательно объявлять и инициализировать переменную только непосредственно перед ее использованием. Если значение для инициализации не может быть определено, потребность в переменной должна быть переоценена. Это делается для того, чтобы избежать ненужного использования памяти и улучшить читаемость кода из-за уменьшенной области видимости. В Java из этих 3 переменных только одна должна быть инициализирована перед ее использованием, иначе компилятор выдаст ошибку. Другими словами, локальные переменные не имеют значений по умолчанию. Ниже приведена таблица различных типов и их значений по умолчанию. Здесь ссылочные типы включают в себя оболочки примитивных типов.
байт, короткий, int, длинный | 0 |
поплавок, двойной | 0.0 |
обуглить | \u0000 |
логический | ложный |
Ссылочный тип | нулевой |
Прежде чем разбираться в таком поведении компилятора, необходимо понять, что это за переменные и чем они отличаются друг от друга.
Статические переменные Статические переменные (или переменные класса) – это глобальные переменные, доступные всем программам в запущенном экземпляре JVM. Они объявляются в классах или интерфейсе с ключевым словом static
. К ним можно получить доступ с помощью dot .
оператор, использующий имя класса/интерфейса. Ниже приведены их особенности,
- Загружается в память, когда класс загружается еще до того, как объект класса создается
- Не участвуйте в сборе мусора
Эти переменные можно оставить неинициализированными после объявления, и им присваивается соответствующее значение по умолчанию. Если статическая
переменная объявлена final
, она не будет принимать значение по умолчанию. Он должен быть инициализирован либо во время объявления, либо может быть инициализирован в специальном блоке в классе с именем Static Initializer . Не окончательная статическая переменная может быть использована/изменена в любом месте.
Переменные экземпляра Java – это объектно-ориентированный язык программирования. Все в java заключено в класс. Класс обладает свойствами и может выполнять действия. Свойства называются переменными экземпляра. Переменная экземпляра уникальна для каждого созданного объекта. К ним можно получить доступ с помощью dot .
оператор, использующий имя объекта. Ниже приведены их особенности,
- Участвуйте в сборе мусора, как только они выйдут за рамки
- Область действия находится внутри объекта и не может быть доступна за его пределами.
- Может быть доступен/изменен только внутри нестатического метода
Эти переменные также можно оставить неинициализированными, как и статические переменные, и они автоматически инициализируются значениями по умолчанию. Если переменная экземпляра объявлена final
, она должна быть либо инициализирована во время объявления, либо в конструкторе, либо в специальном блоке, называемом Инициализатор экземпляра .
Локальные переменные Локальные переменные – это те, которые объявляются внутри метода. Они должны быть инициализированы некоторым значением, при сбое которого компилятор выдаст ошибку. Область действия локальной переменной находится внутри метода, и доступ к ней за его пределами невозможен. Эти переменные хранятся в стеке и извлекаются после завершения вызова метода. Для ссылочных типов объект, на который он ссылается, находится в куче, тогда как тип – в стеке.
Приведенный ниже пример кода показывает поведение статической, локальной и переменной экземпляра.
public class Variable{ public static String staticVariable; private final int instanceVariable; public boolean defaultInstanceVariable; // Static Initializer Block static { System.out.println("Static Initializer Block"); staticVariable= "Static Variable Example"; System.out.printf("staticVariable After Initialization = %s\n",staticVariable); } // Instance Initializer Block { System.out.println("Instance Initializer Block"); instanceVariable= 1; System.out.printf("instanceVariable After Initialization = %d\n",instanceVariable); } // Constructor Block public Variable(){ System.out.println("Constructor Block"); System.out.printf("defaultInstanceVariable = %b\n",defaultInstanceVariable); } // Static Method public static void staticMethod(){ System.out.println("Static Method"); } // Instance Method public void instanceMethod(){ char localVariable = '!'; System.out.println("Instance Method"); System.out.printf("localVariable After Initialization = %c\n",localVariable ); } } //Call 1: new Variable().instanceMethod(); //Output 1: /** Static Initializer Block staticVariable After Initialization = Static Variable Example Instance Initializer Block instanceVariable After Initialization = 1 Constructor Block Instance Method localVariable After Initialization = ! **/ //Call 2: Variable.staticMethod(); //Output 2: /** Static Initializer Block staticVariable After Initialization = Static Variable Example Static Method **/
Почему только локальные переменные?
В Java только локальные переменные имеют очень ограниченную область действия (метод) и время жизни. И у них есть предсказуемый маршрут выполнения, который понимает компилятор. Эти переменные не выходят за рамки метода. Компилятор может определить, где объявлена переменная, и может очень эффективно дать указание программисту инициализировать переменную перед ее использованием. Когда переменная используется без инициализации, существует вероятность потенциальной ошибки в программе. Кроме того, инициализация каждой переменной значением по умолчанию негативно сказывается на производительности. На самом деле это помощь компилятора в улучшении программы. Фактический вопрос должен звучать так: почему компилятор не помогает не использовать статическую переменную/экземпляра перед инициализацией ?
Ответ на этот вопрос заключается в сложности или большем количестве способов доступа к этим переменным. Когда дело доходит до метода, путь выполнения очень ясен. Компилятор может очень хорошо проследить маршрут от использования переменной обратно к ее объявлению. Нет никакого уникального потока, который компилятор мог бы идентифицировать для статической переменной/экземпляра, которая должна быть установлена со значением. Инициализация может происходить в совершенно другой программе, и использование может происходить в каком-то другом месте. Поскольку определенного пути нет, а путь к карте не является узкой линией, им предоставляются значения по умолчанию. Значение по умолчанию определенно лучше, чем неопределенное/случайное значение. Если эти переменные не инициализированы, они могут иметь любое значение для них, и это может быть от нерелевантных данных до конфиденциальных данных.
🔥
Оригинал: “https://dev.to/vivekworks/why-local-variables-need-to-be-initialized-in-java-3pgo”