为什么调用重写方法的超类引用看起来是多态的,但如果它采用重写的成员变量则不是?

Why does a superclass reference calling an overridden method appear polymorphic, but not if it takes an overridden member variable?

package main.java;

public class Demo {
        public static void main(String[] args) {
        BClass bClass=new BClass("han","男");
        AClass aClass=bClass;
        System.out.println(aClass.getSex());
        System.out.println(aClass.sex);
    }
}

这个class的执行结果是

男
null

结果让我感到困惑。当superclass调用重写方法时,结果符合我的预期,但是当它调用重写变量时,结果令人困惑me.so为什么会出现调用重写方法的superclass引用多态的,但如果它需要一个覆盖的成员变量就不是?这是完整的代码。

package main.java;

public class Demo {
        public static void main(String[] args) {
        BClass bClass=new BClass("han","男");
        AClass aClass=bClass;
        System.out.println(aClass.getSex());
        System.out.println(aClass.sex);
    }
}
package main.java;

public class AClass {
    private String name;

    public String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

}

package main.java;

public class BClass extends AClass{

    private String sex;

    public BClass(String name,String sex) {
        this.sex = sex;
        super.setName(name);
    }

    @Override
    public String getSex() {
        return sex;
    }

    @Override
    public void setSex(String sex) {
        this.sex = sex;
    }

}

虽然您可以重写方法,但不能重写子程序中的字段class;您实际上只是在声明一个具有相同名称的字段。要允许该字段在子 class 中也可见,您可以将其可见性更改为 protected 或 package private(默认修饰符),如果两个 classes 在同一个包中。 Demo.

public class BClass extends AClass{
 
    public BClass(String name,String sex) {
        this.sex = sex;
        super.setName(name);
    }
 
    @Override
    public String getSex() {
        return sex;
    }
 
    @Override
    public void setSex(String sex) {
        this.sex = sex;
    }
 
}
public class AClass {
    protected String name, sex;
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getSex() {
        return sex;
    }
 
    public void setSex(String sex) {
        this.sex = sex;
    }
 
}

根据 Java 规范,实例变量在扩展时不会被子 class 从超 class 覆盖。

Java 不允许您真正覆盖字段。

您的 BClass 实际上有两个名为 sex 的字段,一个来自 AClass,一个来自 BClass。 Java 语法并不能真正帮助你找出像 x.sex 这样的东西是指哪个。就好像您定义了两个不同的字段,AClass 中的 sex_aBClass 中的 sex_b,只是引用两者的复杂性写成 x.sex , 没有明确提示这里指的是两者中的哪一个。

你的情况:

  • 您的 BClass 实例将初始化其 sex_b,并且 sex_a 为空(null)。
  • aClass.getSex() 总是根据实例的运行时间 class 调用最具体的方法,即 BClass。所以它从 BClass 中选择方法,返回 sex_b,从而打印性别。
  • aClass.sex 访问两个 sex 字段之一,具体取决于变量的 compile-time-deducible 类型,在您的例子中是 AClass。所以它打印 sex_a 值,为 null。

经验丰富的 Java 开发人员通常会尽力避免这种情况,因为它可能会非常混乱。

如果这两个字段在概念上具有相同的含义,请按照您对 name 字段所做的那样进行操作,父字段 class 中只有一个字段,而子字段 class 通过 getter 和 setter 访问它(或通过声明该字段的 protected 可见性)。

如果这两个字段在概念上具有不同的含义(一个对象可以有两个不同的性别吗?),请使用不同的名称。