问题描述
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);
}
}
此类的执行结果为
男
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;
}
}
解决方法
虽然您可以覆盖方法,但不能覆盖子类中的字段;您实际上只是在声明一个具有相同名称的字段。为了使该字段在子类中也可见,如果两个类都在同一包中,则可以将其可见性更改为class MainActivity : AppCompatActivity(),View.OnClickListener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
num1.setOnClickListener(this)
num2.setOnClickListener(this)
num3.setOnClickListener(this)
num4.setOnClickListener(this)
num5.setOnClickListener(this)
num6.setOnClickListener(this)
num7.setOnClickListener(this)
num8.setOnClickListener(this)
num9.setOnClickListener(this)
}
override fun onClick(view: View?) {
val currentValue = mainText.text
val numberPressed = (view as Button).text
mainText.setText("${currentValue}${numberPressed}")
}
}
或包私有(默认修饰符)。 Demo。
protected
,
按照Java规范,扩展实例类时,实例变量不会从超类中被子类覆盖。
,Java不允许您真正覆盖字段。
您的BClass
实际上有两个名为sex
的字段,一个来自AClass
,一个来自BClass
。 Java语法并不能真正帮助您在编写x.sex
之类的代码时找出含义是什么。就像您已经定义了两个不同的字段一样,sex_a
中的AClass
和sex_b
中的BClass
,只是复杂的是对这两个字段的引用都像x.sex
,但没有明确提示这两个是这里的意思。
在您的情况下:
- 您的BClass实例将初始化其
sex_b
,并且sex_a
为空(空)。 -
aClass.getSex()
始终根据实例的运行时类调用最特定的方法BClass
。因此,它从BClass
中选择方法,返回sex_b
,从而打印出性别。 -
aClass.sex
访问两个sex
字段之一,具体取决于变量的编译时可推导类型,在您的情况下为AClass
。因此它将打印sex_a
值,为null。
经验丰富的Java开发人员通常会尽力避免这种情况,因为这可能会造成混乱。
如果两个字段在概念上具有相同的含义,请像对待name
字段那样进行操作,在父类中只有一个字段,并让子类通过getter和setter(或通过声明protected
字段的可见性。
如果这两个字段在概念上具有不同的含义(一个对象可以具有两种不同的性别吗?),请使用不同的名称。