提要:①子类继承父类,覆盖与重写;②父类声明子类的实例,该如何调用子类方法?父类中如果没有定义子类中的方法,又该如何调用?③什么是上溯造型?什么是下溯造型?
以一道 Java 题目来讨论。推荐自己先写一遍题目再看下面内容~
继承:实现如下类之间的继承关系,并编写Music类来测试这些类。 一步一步分析这道题目:
① 一共有四个类:Music 类、Instrument 类、Wind 类和 Brass 类。先写出空方法,再根据要求补充内容。
public class Music {
public static void main(String args[]){}
public static void tune(Instrument i){}
}
class Instrument{
public void play(){}
}
class Wind extends Instrument{
public void play(){}
public void play2(){}
}
class Brass extends Instrument{
public void play(){}
public void play2(){}
}
② 因为 Wind 类和 Brass 类均继承于 Instrument 类。先写 Instrument 类。
class Instrument{
public void play(){ System.out.println(“弹奏乐器”); }
}
③ 而 Wind 类和 Brass 类非常相似,就一起写了。此时子类继承了父类的属性和方法,但不能继承父类的构造方法、带 private 修饰符的变量和方法。当子类和父类的成员变量同名时,父类的成员变量会被隐藏;当子类和父类的方法同名同参同返回值类型时,子类重写父类方法。
class Wind extends Instrument{
public void play(){ System.out.println(“弹奏Wind”); }
public void play2(){ System.out.println(“调用wind的play2”); }
}
class Brass extends Instrument{
public void play(){ System.out.println(“弹奏Brass”); }
public void play2(){ System.out.println(“调用brass的play2”); }
}
④ 主类为 Music 类,其中的 main 方法仅用作调用主类中的 tune 方法,且以 Wind 类和 Brass 类对象分别为参数。在调用 tune 方法时输入的参数,相当于 “Instrument i = new Wind(); “ 和 “Instrument i = new Brass(); “。
这一部分属于上溯造型:将一种类型(子类)对象的引用转换成另一种类型(父类)对象引用。父类定义子类的实例,或者说父类对象由子类实例化。(从一个特殊、具体的类型到一个通用、抽象类型的转换)
public static void main(String args[]){
tune(new Wind()); // 相当于 Instrument i = new Wind();
tune(new Brass()); // 相当于 Instrument i = new Brass();
}
public static void tune(Instrument i){
i.play();
i.play2(); //此句会报错!原因是父类中没有声明这个子类方法。
}
⑤ 那么 tune 方法如何父类中未声明的子类方法?(即如何调用子类的 play2() 方法)
(1) 第一个解决办法:在父类中声明一个空的子类方法。但题目中 Instrument 类中只有一个方法,此方法不符合题意。那么还有别的方法吗?
public static void tune(Instrument i ){
i.play();
i.play2();
}
class Instrument{
public void play(){ System.out.println(“弹奏乐器”); }
public void play2(){}
}
(2) 第二个解决办法:执行下溯造型,即强制类型转换,将父类类型的引用转换为子类类型(下溯不一定安全,所以需要进行类型检查,即 instanceof )。
public static void tune(Instrument i ){
i.play();
if(i instanceof Wind){
Wind w=(Wind)i;
w.play2();
}
if(i instanceof Brass){
Brass b=(Brass)i;
b.play2();
}
}
至此程序完成。
最后推荐一本书《 Java 语言程序设计(第二版) 》,作者郎波,(最新版是第三版,不过我没有读过…)适合入门的朋友巩固和提高。当我在搜索 “父类定义子类实例 怎么调用子类方法”,很多人都说 “在调用子类方法时,只能调用父类中已声明的”。书中相关章节完美打破这个“只能”。
另,这本书 “第4章 Java面向对象特性” 中讲述了上溯造型和下溯造型,上面部分概念大多引用书中原话。