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

Java 为什么调用重写方法的超类引用看起来是多态的,但如果它接受重写的成员变量?;,java,bytecode,Java,Bytecode,这个类的执行结果是 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()); Sys

这个类的执行结果是

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);
    }
}
结果令我困惑。当超类调用重写的方法时,结果满足我的期望,但当它调用重写的变量时,结果让我感到困惑。那么,为什么调用重写的方法的超类引用看起来是多态的,而如果它使用重写的成员变量则不是多态的呢?下面是完整的代码


虽然可以重写方法,但不能重写子类中的字段;实际上,您只是用相同的名称声明了一个字段。要允许字段在子类中也可见,可以将其可见性更改为
受保护
或包专用(默认修饰符),如果两个类都在同一个包中


虽然可以重写方法,但不能重写子类中的字段;实际上,您只是用相同的名称声明了一个字段。要允许字段在子类中也可见,可以将其可见性更改为
受保护
或包专用(默认修饰符),如果两个类都在同一个包中


根据Java规范,实例变量在扩展时不会被子类从超类重写。

根据Java规范,实例变量在扩展时不会被子类从超类重写。

Java不允许您真正重写字段

您的
BClass
实际上有两个名为
sex
的字段,一个来自
AClass
,另一个来自
BClass
。当您编写类似
x.sex
的东西时,Java语法并不能真正帮助您找出这是什么意思。这就好像你定义了两个不同的字段,
AClass
中的
sex\u a
BClass
中的
sex\u b
,只是复杂的是,对这两个字段的引用都写得像
x.sex
,没有明确的提示这两个字段是什么意思

就你而言:

  • 您的b类实例将初始化其
    sex\u b
    ,并且
    sex\u a
    为空(null)
  • aClass.getSex()。因此,它从
    BClass
    中选择方法,返回
    sex\u b
    ,从而打印性别
  • aClass.sex
    访问两个
    sex
    字段中的一个,具体取决于变量的编译时可推断类型(在您的情况下是
    aClass
    )。因此,它打印
    sex\u a
    值,为空
经验丰富的Java开发人员通常会尽最大努力避免这种情况,因为这可能会非常混乱

如果这两个字段在概念上具有相同的含义,请像处理
名称
字段一样,在父类中只有一个字段,并让子类通过getter和setter(或通过声明该字段的
受保护
可见性)访问该字段


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

Java不允许您真正重写字段

您的
BClass
实际上有两个名为
sex
的字段,一个来自
AClass
,另一个来自
BClass
。当您编写类似
x.sex
的东西时,Java语法并不能真正帮助您找出这是什么意思。这就好像你定义了两个不同的字段,
AClass
中的
sex\u a
BClass
中的
sex\u b
,只是复杂的是,对这两个字段的引用都写得像
x.sex
,没有明确的提示这两个字段是什么意思

就你而言:

  • 您的b类实例将初始化其
    sex\u b
    ,并且
    sex\u a
    为空(null)
  • aClass.getSex()。因此,它从
    BClass
    中选择方法,返回
    sex\u b
    ,从而打印性别
  • aClass.sex
    访问两个
    sex
    字段中的一个,具体取决于变量的编译时可推断类型(在您的情况下是
    aClass
    )。因此,它打印
    sex\u a
    值,为空
经验丰富的Java开发人员通常会尽最大努力避免这种情况,因为这可能会非常混乱

如果这两个字段在概念上具有相同的含义,请像处理
名称
字段一样,在父类中只有一个字段,并让子类通过getter和setter(或通过声明该字段的
受保护
可见性)访问该字段

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

男
null
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;
    }

}

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;
    }
 
}