Разрешение наследования java в случае экземпляров методов и переменных

В соответствии с java, разрешение метода экземпляра основано на типах аргументов времени выполнения.

Но при разрешении переменной экземпляра он использует другой подход, как показано ниже.

Вывод программы - это.

Child
Parent
ParentNonStatic

Здесь Первый вывод основан на типах времени выполнения аргумента, но третий выход не является.

может кто-нибудь объяснить об этом?

  public class Child extends Parent {

        public static String foo = "Child";
        public String hoo = "ChildNonStatic";

        private Child() {
            super(1);
        }

        @Override
        String please() {
            return "Child";
        }

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

           //Resolving method
            System.out.println(((Parent) c).please());

           //Resolving Static Variable
            System.out.println(((Parent) c).foo);

           //Resolving Instance Variable
            System.out.println(((Parent) c).hoo);
        }
    }
class Parent {

    public static String foo = "Parent";
    public String hoo = "ParentNonStatic";

    public Parent(int a) {
    }

    public Parent() {
    }

    String please() {
        return "Tree";
    }
}

Ответ 1

В Java вы фактически не "бросаете". Java на самом деле ничего не делает, когда вы запрашиваете листинг, за исключением проверки того, может ли объект быть передан этому типу, поэтому касты могут вызывать "ClassCastException".

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

В отношении статических полей компилятор фактически удаляет любые переменные экземпляра и ссылается на поле через класс по типу возвращаемого типа.

Parent p = new Parent();
Child c = new Child(); 
Parent pc = new Child();

System.out.println(c.foo); // will print Child
System.out.println(p.foo); // will print Parent
System.out.println(pc.foo); // will print Parent
System.out.println(((Child)pc).foo) // will print Child

Поля, похоже, работают одинаково.

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

Ответ 2

Когда вы поднимаете объект, вы фактически не изменяете содержимое элемента, на который вы ссылаетесь, только так, как вы его рассматриваете. Поэтому, когда вы повышаете c до родителя и вызываете "пожалуйста" (), вы вызываете "пожалуйста" () на родителя, но динамический тип по-прежнему является дочерним, поэтому на самом деле вызывается переопределенная версия у ребенка и печатается "Child".

Когда вы пересказываете c и ссылаетесь на foo, вы не выполняете вызов функции. Компилятор может определить во время компиляции то, о чем вы говорите. В этом случае поле foo объекта, имеющего родительский тип. Поля и статические поля не переопределяются. Вместо этого они скрыты. То, что вы на самом деле делаете с этим повышением, помогает Java выбрать скрытую версию (родительскую), а не ту, что у ребенка. Аналогично, с hoo вы получаете версию родителя.

Вот некоторая информация из учебника JAva: http://java.sun.com/docs/books/tutorial/java/IandI/hidevariables.html

Ответ 3

Поля не переопределяются точно так же, как и методы. Отправляя c в Parent, вы указываете, что ".hoo" относится к полю "hoo" на Parent, а не к Child. (Чтобы сделать его более технически правильным, доступ к полям не является полиморфным.)