起因:为什么写这篇文章,是因为网上看到一道笔试题,作者的解析是错误的,所以在此探讨一下。
题目如下,选择以下代码的输出结果:
class A{
public String s = "A";
public void setS(String s){
this.s = s;
}
public String getS(){
return this.s;
}
}
public class B extends A{
public String s = "B";
public void setS(String s){
this.s = s;
}
public String getS(){
return this.s;
}
public static void main(String[] args){
A a = new A();
B b = new B();
a.setS("[AA]");
b.setS("[BB]");
a = b;
System.out.print(a.s);
System.out.print(b.s);
System.out.print(a.getS());
System.out.print(b.getS());
}
}
A.AB[AA][BB]
B.[AA][BB][AA][BB]
C.A[BB][BB][BB]
D.A[BB]][AA][BB]
跑一下代码,我们马上能够得出结果肯定是选C,但是为什么选C呢?
本题有三个关键点:
1、B继承了A类,但是A和B类中都同时定义了s成员变量
2、B类中的setS重写了A类中的setS方法
3、a = b这条语句的意义
解析:
第一个关键点:
B b = new B();其实存在两个s,在内存中小b引用的对象其实有两个s,父类的s=“A",子类的s=”B“,这个特性其实就是Java中的类的成员属性是静态绑定的,父类和子类中可以定义重名的成员变量,各自独立,不会覆盖,内存结构如下:
第二个关键点不用解释,Java多态技术的基础,存在继承和重写
第三个关键点,也是最重要的关键点就是a = b后的内存结构,此时new A()已经没有用了,此时a和b两个变量其实都指向了new B()的内存
首先,需要理解Java多态定义的前提,因为变量a是A类型的,只能访问它实际类型中的成员,所以:
System.out.print(a.s); // a.s此时访问的是b对象父类的s,就是创建b对象时初始化为父类A时的s
System.out.print(b.s); // b.s此时方法的是b对象B类定义的s,但是这个s被b.setS("[BB]")重新赋值为[BB]了,得到[BB]
System.out.print(a.getS()); // 这里是因为多态机制,调用的是b对象B类定义的getS方法,返回b的s,[BB]
System.out.print(b.getS()); // 这里就没啥可说的了,b调自己的方法,返回b的s,[BB]
以上就是此题完整解释,谢谢