Где видны переменные
В языке 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-блок для статических переменных. Зачем же он нужен, ведь все его содержимое можно написать в начале конструктора? В тех случаях, когда конструктор написать нельзя, а именно, в безымянных внутренних классах.