Скрытие переменных

Возьмем класс

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, думая, что это поле класса.

Современные среды разработки помогают эту проблему частично решить, подсвечивая поля класса. Но проблема, особенно у новичков, сохраняется.

ОК! ИДЕМ ДАЛЬШЕ!