Где видны переменные
В языке Java нестатические переменные можно объявлять в любом месте кода между операторами. Статические переменные могут быть только полями класса, а значит, не могут объявляться внутри методов и блоков. Какова же область видимости (scope) переменных? Из каких методов мы можем обратиться к той или иной переменной? В каких операторах использовать? Рассмотрим на примере листинга 2.6 разные случаи объявления переменных.
Листинг 2.6. Видимость и инициализация переменных.
class ManyVariables{ static int x = 9, у; // Статические переменные – поля класса // Они известны во всех методах и блоках класса // Переменная у получает значение 0 static{ // Блок инициализации статических переменных // Выполняется один раз при первой загрузке класса после // инициализаций в объявлениях переменных х = 99; // Оператор выполняется вне всякого метода! } int а = 1, р; // Нестатические переменные – поля экземпляра // Известны во всех методах и блоках класса, в которых они //не перекрыты другими переменными с тем же именем // Переменная р получает значение 0 { // Блок инициализации экземпляра // Выполняется при создании, каждого экземпляра после // инициализаций при объявлениях переменных р = 999; // Оператор выполняется вне всякого метода! } static void f(int b){ // Параметр метода b – локальная // переменная, известна только внутри метода int a = 2; // Это вторая переменная с тем же именем "а" // Она известна только внутри метода f() и // здесь перекрывает первую "а" int с; // Локальная переменная, известна только в методе f() //Не получает никакого начального значения //и должна быть определена перед применением { int с = 555; // Ошибка! Попытка повторного объявления int х = 333; // Локальная переменная, известна только в этом блоке } // Здесь переменная х уже неизвестна for (int d = 0; d < 10; d++){ // Переменная цикла d известна только в цикле int а = 4; // Ошибка! int e = 5; // Локальная переменная, известна только в цикле for е++; // Инициализируется при каждом выполнении цикла System.out.println("e = " + e); // Выводится всегда "е = 6" } // Здесь переменные d и е неизвестны } public static void main(String!] args){ int a = 9999; // Локальная переменная, известна // только внутри метода main() f (a); } }
Обратите внимание на то, что переменным класса и экземпляра неявно присваиваются нулевые значения. Символы неявно получают значение '\u0000', логические переменные – значение false, ссылки получают неявно значение null.
Локальные же переменные неявно не инициализируются. Им должны либо явно присваиваться значения, либо они обязаны определяться до первого использования. К счастью, компилятор замечает неопределенные локальные переменные и сообщает о них.
Внимание
Поля класса при объявлении обнуляются, локальные переменные автоматически не инициализируются.
В листинге 2.6 появилась еще одна новая конструкция: блок инициализации экземпляра (instance initialization). Это просто блок операторов в фигурных скобках, но записывается он вне всякого метода, прямо в теле класса. Этот блок выполняется при создании каждого экземпляра, после инициализации при объявлении переменных, но до выполнения конструктора. Он играет такую же роль, как и static-блок для статических переменных. Зачем же он нужен, ведь все его содержимое можно написать в начале конструктора? В тех случаях, когда конструктор написать нельзя, а именно, в безымянных внутренних классах.