代码如下:
/**
* 父类
* @author rongxinhua
*
*/
public class Father{
private String name="FATHER";
public Father(){
whoAmI();
tellName(name);
}
public void whoAmI(){
System.out.println("Father says, I am " + name);
}
public void tellName(String name){
System.out.println("Father's name is " + name);
}
}
* 父类
* @author rongxinhua
*
*/
public class Father{
private String name="FATHER";
public Father(){
whoAmI();
tellName(name);
}
public void whoAmI(){
System.out.println("Father says, I am " + name);
}
public void tellName(String name){
System.out.println("Father's name is " + name);
}
}
/**
* 子类
* @author rongxinhua
*
*/
public class Son extends Father{
private String name="SON";
public Son(){
whoAmI();
tellName(name);
}
public void whoAmI(){
System.out.println("Son says, I am " + name);
}
public void tellName(String name){
System.out.println("Son's name is " + name);
}
}
问题:当执行 Father who = new Son(); 时,会输出什么?* 子类
* @author rongxinhua
*
*/
public class Son extends Father{
private String name="SON";
public Son(){
whoAmI();
tellName(name);
}
public void whoAmI(){
System.out.println("Son says, I am " + name);
}
public void tellName(String name){
System.out.println("Son's name is " + name);
}
}
结果为:
Son says, I am null
Son's name is FATHER
Son says, I am SON
Son's name is SON
下面两个打印结果很容易想到。但是前面两个就有点摸不着头脑。我一开始也难以理解,主要是考虑的方向错误,误以为是与初始化顺序有关的题目。但其实是一道关于”重写“的题目。
解答:
Son的两个方法whoAmI和tellName重写了父类的方法,这一点是毋庸置疑的。这里有一点:重写是静态的,重写的过程在编译时就完成了,而重载则是动态的(延迟绑定)。所以当执行 Father who = new Son(); 时,实际的执行顺序如下
1. Son的whoAmI()方法:System.out.println("Father says, I am " + name);看起来有点奇怪,这不都一样吗?的确差不多。但是name不同!3与4的name是Son德name属性(这很容易理解)。
2. Son的tellName(String name)方法:System.out.println("Son's name is " + name);
3. Son的whoAmI()方法:System.out.println("Father says, I am " + name);
4. Son的tellName(String name)方法:System.out.println("Son's name is " + name);
2的name是方法参数传过来的,而且是在父类的构造函数中执行的,那么name的值应该是父类的name属性。可能有点不理解,那么在父类的构造函数中加上一句
System.out.println("Father says, I am " + name);
得到的结果是”Father says, I am FATHER“。所以name属性在父类的构造方法中的确为”Father“且传给了被重写的tellName方法。
1的name值又为什么为null呢?因为whoAmI方法中的name值直接来自类的实例变量。或许你认为Father的name值应该传给它,不就打印出Son's name is FATHER吗?其实不是。虽然变量名都是name,但是这两个变量是不同的。在编译成字节码的时候这两个变量就区分出来了。Java中方法可以重写,但类的属性不行。对此你可以把name的访问权限都改成public结果仍旧不变。还不理解,那就把Father的name属性名改为name_f,并且在子类的whoAmI方法中加入如下代码:
super.whoAmI();
得到的结果为:
Son says, I am null可见父类的whoAmI方法仍旧可以正常打印结果。这样理解就方便多了!
Son's name is FATHER
Father says, I am FATHER
Son says, I am SON
Son's name is SON
结论:从这到题可以知道几点:
Java的重写是在编译成字节码时执行的。
Java的方法可以重写但是变量不行。
父类的变量会被保留,如果此变量的权限不为private,则可以通过super来访问。
被重写的方法中引用的实例变量是子类的变量,即使与父类变量名重复,也不会在父类的执行环境中(如构造函数)使用父类变量。
被重写的父类方法可以用super访问。
没有评论:
发表评论