代码很重要!!!其他都是废话。把代码看懂,最好自己写一遍。
继承。“在软件开发中继承就是子类可以使用从父类继承的属性和方法。”–百度百科。(开篇度娘来镇楼)作为面向对象三剑客,继承在OOP中举足轻重,对于代码复用就有重要意义。在学习继承时,老师都会由父类子类来反复讲解继承的概念及其中注意事项。很多人就在这辩证讲解中绕了进去。今天,就由3个Java例子来细细阐述继承的爱恨情仇。。。
一言不合就上码(PS–>张宇:上来!······)
ChineseFood.java
class Food{
public Food() {
System.out.println("食物 构造方法");
}
}
//中国菜继承Food
class ChineseFood extends Food{
public ChineseFood() {
System.out.println("中国菜 构造方法");
}
private String cFood = "中国菜";
//此处 += 构成重载。
public void cook(String a){ cFood += a;}
public void chao(){cook(" 炒");}
public void shao(){cook(" 烧");}
public void jian(){cook(" 煎");}
public void zha(){cook(" 炸");}
public String toString(){return cFood;}
public static void main(String[] args){
ChineseFood c = new ChineseFood();
c.chao();
c.shao();
c.jian();
c.zha();
//由于toString()方法的存在下面调用时输出的不是ChineseFood对象。
System.out.println(c);
}
}
SichuanCuisine.java
//川菜继承中国菜
public class SichuanCuisine extends ChineseFood{
public SichuanCuisine() {
System.out.println("川菜 构造方法");
}
public void chao(){
super.chao();
cook(" 炒在川菜中演化出溜");
}
public void hua(){
cook(" 滑");
}
public static void main(String[] args){
SichuanCuisine s = new SichuanCuisine();
s.chao();
s.shao();
s.jian();
s.zha();
//川菜有滑的烹饪方法。
s.hua();
//SichuanCuisine继承了ChineseFood,隐式的覆写了父类的toString()方法。
System.out.println(s);
System.out.println("测试中国菜:");
//可以在一个类的方法中调用另一个类的主函数。
ChineseFood.main(args);
}
}
- 以上两个Java文件中定义了三个类。SichuanCuisine类继承ChineseFood类,ChineseFood类继承Food类。下面就通过这个栗子来阐述继承。
- 1、子类继承父类后,就会自动得到基类中所有的域和方法。SichuanCuisine继承了ChineseFood类,就会自动得到父类中的域和方法。所以,SichuanCuisine中没有显示定shao();jian();zha();的方法。但SichuanCuisine中第16行至18行可以调用这三个方法。
- 2、子类可以具有父类没有的方法。例如:滑的烹饪方法是个别菜系的方法,而不是中国菜的共有方法。那么我们在代码中就要把这种子类特殊的方法写到子类中。对应的就是:SichuanCuisine类中定义了一个父类中没有的方法hua()。
- 3、子类可以在覆写的父类方法中加入自己的特有逻辑。还是举菜的例子:在ChineseFood里chao()是各大菜系共有的方法,但川菜在传统炒的基础上发展处了“溜”的烹饪技巧。正如代码第6行至第9行方法中,子类覆写了父类chao()方法,带在其中又加入了自己特有的方法。
- 4、Java会在父类的的构造函数中插入对子类构造函数的调用,父类在子类访问它之前就完成了初始化。为了方便大家理解,我把三个类的构造函数都显示地写了出来。SichuanCuisine第14行,在new出来对象s的时候,底层会先调用Food的构造函数,再调用ChineseFood的构造函数再调用SichuanCuisine的构造函数。这就是很多老师讲的:子类的实例化一定伴随父类的实例化。
- 5、调用父类方法时用super。在SichuanCuisine的chao方法中想调用父类chao方法,就用super.chao();。
这个栗子中还有三个值得深究的地方。就当是福利白送了。 - A、ChineseFood.java第14行,中“+=”符号。很多初学者就把它理解为基本运算符中的“+=”,其实此“+=”非彼“+=”;此“李逵”非彼“李逵”。基本运算符运算的基本数据类型,String是基本数据类型嘛?其实这个“+=”是被Java设计者重载过的运算符。用来处理string对象的。
- B、在ChineseFood.java中第26行及SichuanCuisine.java第22行,控制台输出的是一个对象,但实际输出的却不是对应对象的内存地址?留个白吧,来点神秘诱惑(把ChineseFood.java的第18行注释掉试一下),自己尝试去网上找资料解决问题,这是很重要的技能哦。请自行get!
- C、掀开main的盖头来。在类中调用另外一个类的主函数。初始入门时,老师反复强调一个程序只有一个入口,所以很多同学都不约而同的会让自己的项目尽量保有一个main方法。好像main函数是什么洪水猛兽,令人敬而远之。再加上很多Demo中也都有这样的现象,令此甚嚣尘上!但main其实就是隔壁班的羞涩女孩,没有那么神秘。就像SichuanCuisine.java第25行,可以像普通的静态方法一样去调用她。其次,一个类即使不当做项目入口也可以给它一个main方法这种方法还有一个小用处。那就是方便测试。在测试工具泛滥的今天,但对于初学者这也不失一个方便上手的好方法:把mian方法当做单元测试的工具。比如:你写完一个类后,想知道该类有没有实现你需求的功能有没有BUG,可以在该类的main方法中调用来测试一下(本人初学Java时,找错误就是这么干的。插桩快乐!)。关于测试我想多说一点:很多开发者由于开发进度,人力各种原因都忽视测试,其实,测试本身就是软件开发的固有组成部分,神圣而不可忽视!初学者更应该有意思培养。
扩展了那么多,差点把继承都给忘了,那么再说一点继承吧。老规矩:一言不合就上码。
HunanCuisine.java
class FoodA{
public FoodA(int i) {
System.out.println("食物 构造方法");
}
}
class ChineseFoodA extends FoodA{
ChineseFoodA(int i){
super(i);
System.out.println("中国菜 构造方法");
}
}
public class HunanCuisine extends ChineseFoodA{
HunanCuisine(){
super(11);
System.out.println("湘菜 构造方法");
}
public static void main(String[] args) {
HunanCuisine h = new HunanCuisine();
}
}
亲!你上来了吗?开始说到继承的第4点时,将到了构造方法,其实还有一点值得注意。
- 6、父类没有默认构造函数,子类必须显示地调用父类的构造函数,并且调用必须放到第一行。如:HunanCuisine.java中,FoodA中只要有参的构造函数,并且没有显示声明无惨的构造函数(可以理解为没有)。那么ChineseFoodA在继承的时候,就必须显示调用FoodA的构造函数。并且super()必须放到第一行。(可以尝试把它移到下面去看看。)
- 当然,继承作为OOP三剑客不是这三言两语就能完全说完的,正如BAT都不是喷出的。继承还有其他内容,以后再说。
代码很重要!!!其他都是废话。把代码看懂,最好自己写一遍。