Скрытие переменных
Возьмем класс
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, думая, что это поле класса.
Современные среды разработки помогают эту проблему частично решить, подсвечивая поля класса. Но проблема, особенно у новичков, сохраняется.