Скрытие переменных
Возьмем класс
class Cat {
int age = 3;
void incrementAge(int age) {
age = age + 1;
}
}
внутри метода incrementAge объявлен параметр с тем же названием (и типом), что и поле класса: int age
Поэтому внутри метода, при обращении к переменной age видно будет наиближайше объявленную переменную с этим именем (это как раз параметр у метода), а остальные переменные не будут видны/доступны. То есть они будут скрыты. Поэтому это и называется "скрытие переменных".
В большинстве случаев – это является архитектурной ошибкой. Поэтому стоит избегать такого подхода.
В нашем случае увеличится на 1 не поле класса age, а параметр метода.
Чтобы такую ошибку исправить – нужно просто давать разные названия для полей класса и параметров метода.
То есть в нашем примере мы переименуем incrementAge(int age) в incrementAge(int a) и получится так
class Cat {
int age = 3;
void incrementAge(int a) {
age = age + 1;
}
}
Теперь названия у переменных разные и метод incrementAge(int a) действительно увеличивает на 1 значение поля класса.
(Дальше мы заметим, что параметр int a нам не нужен, мы его не используем, поэтому просто его удалим)
И получим результирующий правильный код:
class Cat {
int age = 3;
void incrementAge() {
age = age + 1;
}
}
Рассмотрим еще вариант, как еще может проявиться скрытие
Вот это правильный класс с методом setAge, которому в параметр приходит значение и он это значение сохраняет в поле класса age:
class Cat {
int age = 3;
void setAge(int a) {
age = a;
}
}
Но что будет, если в этом методе мы объявим переменную с тем же именем, что и параметр метода, вот так:
class Cat {
int age = 3;
void setAge(int a) {
int a = 10; // ошибка
age = a;
}
}
в этом случае все проще, сама система покажет, что в строке int a = 10; у нас ошибка, так как переменная с именем a уже определена в этом пространстве фигурных скобок. Ну действительно, в параметрах метода есть же уже int a;
Поэтому эту ошибку мы легко исправим и здесь недопустим "скрытия переменных". У нас просто код не запустится.
А вот когда скрытие касается полей класса – никто нас по умолчанию не предупредит и легко допустить ошибку.
Старайтесь избегать ситуации, когда у вас локальная переменная в методе имеет то же имя, что и поле класса.
Исключением, конечно же, являются параметры метода.
Например, у вас такой код:
public class Game {
private static boolean b = true;
public static void main(String[] args) {
int a = 0;
int b = 0;
for (int i = 0; i < 9; i++) {
if (b > 2) {
b = 0;
a++;
}
// ... и так далее
в нем видно, что есть переменная с именем b в поле класса и с таким же именем – локальная переменная в методе.
У локальной переменной приоритет. А к переменной класса можно обратиться через приставку this. в нашем случае, это будет this.b. Тем не менее, такое скрытие переменных опасно и является очень частой ошибкой. Так как в коде вы можете работать с b, думая, что это поле класса.
Современные среды разработки помогают эту проблему частично решить, подсвечивая поля класса. Но проблема, особенно у новичков, сохраняется.