标签:
前几天在面试的时候又被问到了一个问题,“Java重写和重载有什么区别?”。这个问题在Java领域是一个老生常谈的问题了,事实上我认为这两个东东除了中文名长得很像以外(英文名好像也很像),基本就没半毛钱关系了。我们很难找出他们的共性,却一直要尝试找出他们之间的区别,呵呵。
然而本文的主题并非重写和重载,而是重写的的孪生兄弟,属性继承。
故事的开始,我们先看一段代码
1 public class Parent{
2 public String color;
3 public Parent(){
4 this.color="green";
5 }
6 public void printColor(){
7 System.out.println(color);
8 }
9 public static void main(String args[]){
10 new Child().printColor();
11 }
12 }
13 class Child extends Parent{
14 public String color;
15 public Child(){
16 }
17 public void printColor(){
18 System.out.println(color);
19 }
20 }
这段代码很简单,我们先写了一个类Parent,给他添加了一个属性color,并在构造函数中初始化为“green”,同时提供一个打印函数将color的值输出。
然后我们编写了一个Child类继承Parent,重写color属性,重写打印方法。
我们在main函数里面创建一个Child对象,并调用printColor方法。
那么,输出的结果是什么呢?
答案是null。
很多人会问,你Child类构造函数都没有初始化color,怎么可能有值。
慢着慢着,我们把这段代码改改。
public class Parent{
public String color;
public Parent(){
this.color="green";
}
public void printColor(){
System.out.println(color);
}
public static void main(String args[]){
new Child().printColor();
}
}
class Child extends Parent{
public String color;
public Child(){
}
}
这段代码里面我们只是删掉了子类的printColor方法。运行,结果是green。 事情好像就不那么简单了。 事实上,事情的关键点有三个。
我们一个一个来,首先是继承时构造方法的调用顺序。
是这样的,在几乎所有语言里面,如果想要正确运行一段代码的,前提条件是这段代码的所有依赖都能正常运行。所以,在搞定一段代码之前,都要先搞定他的依赖关系。例如我们加载一个类的时候,要先加载完成类中所有引用到的其他类。对象的创建也是一样,当我们创建一个对象时,首要任务就是“创建父类对象”,父类的构造方法也就是在这个时候调用的。
当我们“创建父类对象”之后明显会碰到一个问题,父类对象创建并初始化所有属性后,子类又打算再创建一个相同的属性,此时会怎样呢?
答案是:而是再创建一个该属性。
于是一个子类对象里面就有了两个同名的属性,一个是父类创建并且初始化为green的color,一个是还没有被初始化的子类的color。那么在printColor方法里面的color到底是哪一个呢?
这里要先说两个规则:
1.“逐级查找,找到则停”。属性和方法都可以适用这条规则。他的大意是,当我们需要调用一个方法或者属性时,我们先看看自己有没有,没有的话,就去上级(父类)找找,直到找到为止。这也可以很好地解释方法重写是如何实现的。不过属性和方法有一点区别,当子类对象向上转型为父类对象后,调用同名方法调用的只可以是子类方法,调用属性则调用父类属性。
2.调用的是谁的方法,属性查找的起点就是谁。这条规则的重点是在于判断调用的究竟是谁的方法。当一个子类重写父类方法时,调用的必然是子类方法,反之则调用的必然是父类的方法。
以上两点看似非常容易理解,现在我们来结合前面的代码理解一下。
第一段代码,当我们调用printColor方法时。
第二段代码
如果以上两个流程你都理解了,那么属性继承你基本上也就掌握了。总结一下关键点。
问题1:当我们处在在第一段代码中的情况,并且想调用父类的color属性打印green方法怎么办呢?
使用super.color就可以访问
同样,使用super.printColor()可以调用父类的printColor()方法。
问题2:如果层级Parent还有一个父类PerParent也有相同属性,我们在Child该怎么才能调用到?
super.super.color?
明显不对。
此时我们只要向上转型即可。(Perparent)child.color;
不过这里要注意的是,方法重写后,使用(Parent)child.printColor()是无法访问到父类方法的。
文章的结尾,我留下两个习题,如果你看一眼能正确给出答案的话,我只能为你默默刷66个6666。
题1:
public class Parent{
public String color;
public Parent(){
this.color="green";
}
public void printColor(){
System.out.println(color);
}
public static void main(String args[]){
new Child().printColor();
}
}
class Child extends Parent{
//我们在这里删掉color属性
//public String color;
public Child(){
}
public void printColor(){
System.out.println(color);
}
}
题2:
public class Parent{
public String color;
public Parent(){
this.color="green";
}
//在这里删掉父类的printColor方法
/* public void printColor(){
System.out.println(color);
}*/
public static void main(String args[]){
new Child().printColor();
}
}
class Child extends Parent{
//我们在这里删掉color属性
//public String color;
public Child(){
}
public void printColor(){
System.out.println(color);
}
}
标签:
原文地址:http://www.cnblogs.com/levi1994/p/5568433.html