Java 与这个简单的多态性示例相混淆

Java 与这个简单的多态性示例相混淆,java,polymorphism,Java,Polymorphism,请查看此代码: class Foo { public int a; public Foo() { a = 3; } public void addFive() { a += 5; } public int getA() { System.out.println("we are here in base class!"); return a; } } public class

请查看此代码:

class Foo {
    public int a;
    public Foo() {
        a = 3;
    }
    public void addFive() {
        a += 5;
    }
    public int getA() {
        System.out.println("we are here in base class!");
        return  a;
    }
}

public class Polymorphism extends Foo{
    public int a;
    public Poylmorphism() {
        a = 5;
    }
    public void addFive() {
        System.out.println("we are here !" + a);
        a += 5;
    }
    public int getA() {
        System.out.println("we are here in sub class!");
        return  a;
    }

    public static void main(String [] main) {
        Foo f = new Polymorphism();
        f.addFive();
        System.out.println(f.getA());
        System.out.println(f.a);
    }
}
在这里,我们将类
多态性
对象的引用指定给类型为
Foo
的变量,即经典的polmorphism。现在我们调用方法
addFive
,该方法在类
多态性中被重写。然后,我们从getter方法打印变量值,该方法也在类多态性中被重写。所以我们得到的答案是10。但是当公共变量
a
被SOP'ed时,我们得到了答案3


这是怎么发生的?尽管引用变量类型是Foo,但它引用的是多态类的对象。那么,为什么访问
f.a
不会导致类
polymorphics
中的a值被打印出来呢?请帮助

您正在隐藏
多态性的
a
——您应该得到一个编译器警告。因此,这是两个不同的
a
字段。与方法相反,字段不能是虚拟的。好的做法是根本不使用公共字段,而只使用改变私有状态(封装)的方法


如果要使其成为虚拟的,则需要将其作为具有访问器方法的属性(例如,您拥有的:
getA
)。

这是因为您不能重写类变量。当访问一个类变量时,引用的类型,而不是对象的类型,决定了您将得到什么


如果删除子类中a的重新声明,那么我认为行为将更符合预期。

有一件事可能会澄清这一点,那就是查找“alpha重命名”的定义这就是这里发生的道德问题。为什么在调用方法时检查对象类型,在获取字段时检查类类型?如果变量也被对象类型引用,结果会是什么?@Shades88,查找虚拟字段意味着执行“getter”代码。字段是对象数据中的偏移量,而方法独立于实际对象数据;它们的地址存储在虚拟方法表中,每个类只存在一次。方法只是在指向对象数据的指针中传递,它们不是数据的一部分。请注意,只要字段是私有的,这就变得无关紧要了,因为除了声明字段的类的方法之外,没有其他代码可以看到它。@Shades88,我确实做了一些与编译器相关的工作,尽管不是在Java世界。快速回顾:“final”(非虚拟)方法在内存中有一个固定地址,它们被调用,第一个参数是“this”(例如实例)。请注意,调用本身不需要了解或访问实例。字段访问是不同的:对于给定类型,字段数据存储在实例数据的哪个偏移量处是已知的。所以这个+field_偏移指向字段数据。现在在普通的OO运行时中,第一个字段是指向类数据的隐藏字段。(续)此类数据不仅用于确定类型,还包含虚拟方法表(VT)。因此,就像一个字段的偏移量在实例数据中是已知的一样,每个虚拟方法在VT中的指针都有一个已知的偏移量,当调用虚拟调用时,编译器只需加载该方法的VT项并调用该指针。请注意,这对实例的内存布局没有任何影响,对于相同的方法,VT中的索引也总是相同的。所以可以说字段是虚拟的,除非你像方法一样执行alpha重命名。哦……那么你能解释一下为什么会这样吗?我的意思是,如果变量也被覆盖,会有什么影响?因为调用mmethods时检查对象类型和获取字段时检查类类型听起来很奇怪;)引用类型决定哪些方法和变量可用于调用。多态性的作用是覆盖这些可用方法的行为。但是,由于不能重写类变量,因此始终会在引用类型的类中获取变量的值。