“初学java,只有问题与心得。”
先引入一个例子:
class Father {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
class Son extends Father{
}
class Test4 {
public static void main(String[] args) {
Son s = new Son();
s.setName("儿子");
System.out.println(s.getName());
}
}
运行打印:儿子
表面看起来没有什么问题,我们仔细分析一下。
1.Son 继承 Father :也就是说Son类继承了父类的get-set方法,但没有继承private修饰的属性name
2.在main方法中,通过对象s调用setName()和getName()。
问题就出现在这:既然子类中没有name这个属性,那么get-set中的name肯定不是子类对象的而应该是父类中的。
如果说子类继承了父类的方法的意思是说子类拥有了父类的方法。
那是不是可以理解为以下代码:
class Father {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
class Son extends Father{
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
class Test4 {
public static void main(String[] args) {
Son s = new Son();
s.setName("儿子");
System.out.println(s.getName());
}
}
答案显然是不行的,编译直接报错:错误: name可以在Father中访问private
也就是说在子类中根本就没有name这个属性,而this代表当前调用方法的对象,因此在get-set方法中的this.name根本不存在。
那么问题又来了,既然子类中没有name这个属性,那么get-set中的name肯定不是子类对象的而应该是父类对象中的。所以get-set里的this应该代表父类对象,也就是说最终将是由父类对象调用get-set方法。
出现了这样的情况,我们似乎只能猜测,子类的方法中通过super关键字访问到父类的私有属性。
一开始我猜测如此:
class Father {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
class Son extends Father{
public void setName(String name) {
super.name = name;
}
public String getName() {
return super.name;
}
}
class Test4 {
public static void main(String[] args) {
Son s = new Son();
s.setName("儿子");
System.out.println(s.getName());
}
}
即在子类中通过super.name访问父类的私有属性,这样似乎就能解决以上的问题。可结果是编译报错:错误: name可以在Father中访问private。跟上个例子一样的错误。因为我们疏忽了,在子类中,不管是直接还是通过super关键字间接,都是不能访问到父类的私有属性的。
想了想,既然this代表父类对象,那是不是说其实在子类对象的堆内存方法区中根本就没有get-set方法。那么子类到底是如何调用到不存在自己堆内存中的方法并成功修改并得到父类的私有属性的呢?这个时候我们又只能猜测,子类对象其实是调用了父类中的get-set方法。
为了验证,又写了段代码:
class Father {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
class Son extends Father{
public void setName(String name) {
super.setName(name);
}
public String getName() {
return super.getName();
}
}
class Test4 {
public static void main(String[] args) {
Son s = new Son();
s.setName("儿子");
System.out.println(s.getName());
}
}
运行打印:儿子
结果终于和第一段代码的结果一致。
总结:在继承中,如果子类没有重写父类的方法,那么在子类对象的内存区中其实是不存在此方法的,那么在通过子类调用方法时,jvm首先会在子类对象空间中查找,找不到就去父类中查找。于是也就出现了所谓子类对象访问到父类私有属性的假象。
到这,问题应该是解决了。