Переэкспонирование метода экземпляра против скрытия поля

Ниже приведен код,

package ClassesOverridingHidingAccess;

interface I{
    int x = 0;
}
class T1 implements I{
    int x = 1;
    String s(){
        return "1";
    }
}

class T2 extends T1{
    int x  = 2;
    String s(){
        return "2";
    }
}

class T3 extends T2{
    int x = 3;
    String s(){
        return "3";
    }

    void test(){
        // Accessing instanc method
        System.out.println("s()=\t\t" + s());   // 3
        System.out.println("super.s()=\t" + super.s()); // 2
        System.out.println("((T2)this).s()= " + ((T2)this).s());  // 3; method is resolved at runtime
        System.out.println("((T1)this).s()= " + ((T1)this).s());  // 3; method is resolved at runtime

        //Accessing instance attribute
        System.out.println("\n\nx=\t\t" + x);  // 3
        System.out.println("super.x=\t" + super.x);  // 2
        System.out.println("((T2)this).x=\t" + ((T2)this).x);  // 2; resolved at compile time
        System.out.println("((T1)this).x=\t" + ((T1)this).x);  // 1; resolved at compile time
        System.out.println("((I)this).x=\t" + ((I)this).x);   // 0; resolved at compile time
    }
}

public class SuperAndInstanceMethods {
    public static void main(String[] args) {
        (new T3()).test();
    }
}

где,

это класс времени выполнения, который учитывается в случае доступа к методу экземпляра.

это вид объекта, который считается в случае доступа к полю.

Приведение не меняет тип класса объекта. Я имею в виду ((T1)this) instanceof T3 является true, если this указывает на объект типа T3,

Итак, каково обоснование правила, которого придерживаются при доступе к полю? Правило, например, методы имеют смысл для меня.

Примечание: для меня непросто помнить эти правила, если на то нет веской причины.

2 ответа

Решение

Методы экземпляра разрешаются через V-таблицу, то есть, как вызывается метод типа времени выполнения. Нет такой таблицы, разрешающей это для полей (или статических методов в этом отношении), поэтому используется тип времени компиляции.

Скрытие полей, а затем делать такие вещи ((T1)this).x это очень необычно, я бы избежал этого, так как не думаю, что это читабельно.

И документы Java подтверждают:

Внутри класса поле с тем же именем, что и поле в суперклассе, скрывает поле суперкласса, даже если их типы различны. Внутри подкласса на поле в суперклассе нельзя ссылаться по его простому имени. Вместо этого поле должно быть доступно через super, что рассматривается в следующем разделе. Вообще говоря, мы не рекомендуем скрывать поля, так как это затрудняет чтение кода.

(Акцент мой)

Таким образом, это должно быть низко в вашем списке правил, чтобы помнить.

Вы можете включить ошибку / предупреждение для этого во всех хороших IDE, вот это в IntelliJ:

Осмотр IntelliJ

Просто придерживайтесь правила большого пальца как:

  1. В случае переопределения метода ссылочная переменная не имеет значения, но имеет значение фактический тип объекта, на который ссылается эта переменная.
  2. В случае затенения / скрытия переменных переменная-ссылка имеет значение, в то время как фактический тип объекта, на который ссылается эта переменная, не имеет значения.

Рассмотрим приведенный ниже пример для ссылки:

public class Parent {
    String name = "Parent";
    public void printName(){
    System.out.println("Parent Method");
  }
}

public class Child extends Parent {
  String name = "Child";
  public void printName(){
    System.out.println("Child Method");
   }
}

Теперь запустим это main() метод в тестовом классе:-

public class Test {

public static void main(String[] args) {
    Parent p = new Parent();
    Child c = new Child();

    System.out.println(p.name); // will print Parent's name
    System.out.println(p.printName());// will call Parent
    System.out.println(c.name); // will print Child's name
    System.out.println(c.printName());// will call Child

    Parent pc = new Child();
    System.out.println(pc.name);// will print Parent's name
    System.out.println(pc.printName());// will call Child
   }
}

Это будет напечатано ниже в соответствии с правилами, которые я изложил выше:

Parent 
Parent Method
Child
Child Method
Parent
Child Method
Другие вопросы по тегам