Почему методы могут быть переопределены, а атрибуты - нет?

У меня есть класс

public class A {
    public String attr ="A attribute";
    public void method() {
        System.out.println(this+" , "+this.attr);
    }
    public String toString() {
        return("Object A");
    }
}

и другой класс, который наследует от него

public class B extends A{
    public String attr = "B attribute";
    public void method() {
        super.method();
    }
    public String toString() {
        return("Object B");
    }
}

Обратите внимание, что method() из B - это просто оболочка для method() из A

Когда я запускаю следующий код

B b = new B();
b.method();

Я получаю Object B, A attribute качестве вывода, что означает, что this и this.attr обращались к разным вещам. Почему это так?

System.out.println(this) ссылаться на метод toString() класса A?

Ответ 1

Объявляя метод с тем же именем, что и родительский класс, вы переопределяете его, то есть заменяете исходное поведение. Но если вы объявляете поле с тем же именем, вы фактически скрываете его, делая его недоступным для этого подкласса, но только с помощью super.field. Смотрите документацию оракула по скрытию переменных, а также по ключевому слову super. Обратите внимание, что не рекомендуется использовать скрытие переменных, так как это создает именно ту путаницу, с которой вы столкнулись.

При вызове super.method() печать this приводит к вызову метода toString, который фактически был переопределен - так что причина, по которой он печатает "Объект B", как вы вызывали метод в экземпляре B. Но this в this.attr фактически ссылается на родительский объект, так как вы вызываете method из родительского класса (с помощью super.method()).