为什么调用重写方法的超类引用看起来是多态的,但如果它采用重写的成员变量则不是?
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_a
和 BClass
中的 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
可见性)。
如果这两个字段在概念上具有不同的含义(一个对象可以有两个不同的性别吗?),请使用不同的名称。
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_a
和 BClass
中的 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
可见性)。
如果这两个字段在概念上具有不同的含义(一个对象可以有两个不同的性别吗?),请使用不同的名称。