java继承
继承是面向对象的语言的一个重要的特性,以下将围绕下面几个点来介绍继承
-
继承的概念
-
super
-
隐藏和覆写
-
继承与组合
-
继承的局限
继承的概念
代码复用是一个令人注目的功能之一,很多的语言的可以实现这个功能(如函数就是为了实现这个功能),但继承与之有些不同,继承不仅可以达到代码复用的功能,往往还可以在现有的功能上得到延展,这也是继承令人喜爱的原因
当多个类之间有相同的属性和行为时,可以将相同的内容提取出来组成一个公共的类,让多个类吸收公共类中已有的特征和行为而多个类只需编写自身特有的特征和行为,叫做继承
注意:继承不要盲目的使用,必须要满足有相同的属性和行为,即必须满足 is-a的关系,继承的类(子类)必须是被继承的类(父类)的一种,如 Work类(子类)是Person类(人类)的一种
- 继承的特点
1.java中支持单继承,不支持多继承。简单来说java中的子类只能继承自一个父类,但一个类可以拥有多个子类(c++中支持多继承)
其实java在c++的基础上进行设计,这一步的更改很有道理,很符合人类的实际生活
2.子类可以继承父类中公有的属性和方法,私有的属性可以继承但不能直接访问,构造方法不能被继承
3.子类中访问父类的属性和方法用super.访问
super关键字
super在继承中是一个很重要的关键字,表示超类即父类,是指向父类的引用
1.在子类中可以用super.访问子类的方法和属性
2.super()表示调用父类的构造方法
在子类的构造方法首行默认添加super(),调用父类的构造方法
这一点很好理解,有父才有子,这很符合现实生活。构造方法是用来给对象赋值,而子类的一些属性继承自父类,调用子类构造方法的同时调用父类的构造方法才能保证子类对象赋值的完整性
注意:在java中如果没有创建构造方法则系统和生成一个无参的构造方法,如果创建了构造方法则系统不会创建无参的构造方法,而子类构造方法的首行会默认调用父类的无参构造,如果此时父类重写了构造并且没有提供无参构造则会报错,
3.super和this
super和this都要求放到构造方法的第一行,所有不能同时出现
隐藏与覆写
- 方法覆写
指的是子类定义了与父类同名的方法
方法覆写的现实意义:如果父类中有一个show方法用于打印父类特征,该show方法被子类继承,如果需要打印子类的特征,调用该继承的方法打印的也只是打印子类继承自父类的特征,无法打印子类特有的特征
此时可以在子类中覆写该show方法,在子类show中调用super.show(),当调用show方法调用的是覆写后的show方法,就可以打印子类全部特征了
class Person{
public String name;
public int age;
public String sex;
public Person(String name,int age,String sex){
this.name=name;
this.age=age;
this.sex=sex;
}
public void show(){
System.out.println("姓名:"+this.name+"年龄:"+this.age+"姓名:"+this.name);
}
}
class Student extends Person{
private double score;
public void show(){
super.show();
System.out.println("分数:"+this.score);
}
public Student(double score){
super("张三",13,"男");
this.score=score;
}
}
public class Extendss{
public static void main(String[]args){
Student st=new Student(78.3);
st.show();
}
}
打印结果:
- 方法覆写的原则
1.要求方法名相同.参数列表相同以及返回值类型相同。从java5开始允许,当父类返回父类类型时,子类返回子类类型
对修饰符的要求
2.要求重写方法的访问空间不能变小,可以变大或者相同
3.要求方法不能抛出更大的异常
属性的隐藏
和方法覆写的概念相同的一个概念为属性覆盖,如果子类的父类申明了相同名称的属性,则在子类中访问时采用就近原则,即先找到本类中的属性,如果要调用父类中的属性采用super.属性调用
属性的隐藏举例:
class Person{
public int age=1;
public String name="李四";
}
class Student extends Person{
public
static void tell(){
System.out.println("hhele");
}
public String name="张三";
public int age=34;
}
public class Extenddd{
public static void main(String[]args){
Student st=new Student();
System.out.println("姓名:"+st.name+"年龄:"+st.age);//姓名:张三年龄:34
}
}
父类相同的属性被隐藏,调用采用就近原则
- 方法的隐藏
用static修饰的方法属于类,无法进行覆写,但构成了隐藏
class Person{
public static void tell(){
System.out.println("helloworld");
}
}
class Student extends Person{
public static void tell(){
System.out.println("what is your name?");
}
}
public class Extenddd{
public static void main(String[]args){
Student st=new Student();
st.tell();//what is your name?
}
}
父类的tell方法被隐藏,调用采用就近原则
- static修饰的方法的多态形式的调用
class Person{
public static void tell(){
System.out.println("helloworld");
}
}
class Student extends Person{
public static void tell(){
System.out.println("what is your name?");
}
}
public class Extenddd{
public static void main(String[]args){
Person st=new Student();
st.tell();//helloworld
}
}
多态向上转型,此时的对象既属于子类又属于父类。此时的对象进行方法或者属性的调用,理解为子类调用,但在父类的范围内这也就可以解释为什么此时的对象为什么不能调用子类特有的方法。此时的对象按照属性覆盖的就近原则就只能调用父类里面的Static方法了
继承与组合
另外一种常见的复用方法就是组合——在新类中创建已有类的对象,通过该对象来调用已有类中的非private的属性和方法;就像程序清单2-1那样。
组合需满足 has-a原则
private Baizhantang boyFriend = new Baizhantang();
public Tongxiangyu() {
System.out.println("我是同福客栈的掌柜佟湘玉");
boyFriend.pointHand("郭芙蓉");
}
public static void main(String[] args) {
new Tongxiangyu();
}
}
class Baizhantang {
Baizhantang() {
System.out.println("我是退隐江湖的盗圣白展堂");
}
public void pointHand(String name) {
System.out.println("那谁" + name + ",准备一下——葵花点穴手");
}
}
从程序清单2-1中我们可以看得出,葵花点穴手虽然是白展堂的绝技,但作为佟掌柜的男朋友,佟掌柜要展堂点个穴,展堂也是不敢推辞的。你看,佟掌柜虽然是个弱女子,但自从有了展堂这个武功数一数二的男朋友,再没有谁敢不听话啊——厉害的组合啊。
需要注意的是,如何在继承和组合之间做出选择呢?
如果新类和已有类需要具有一些相似的方法和属性时,就采用继承的形式;如果新类只是为了借用已有类的一些方法和属性时,而两者没有很多相似之处时就需要采用组合的形式。
-
复用程序选择原则
在进行程序的复用时,优先考虑组合 -
组合和继承优缺点对比
继承的局限性
在java中不支持多继承,虽然人性化,但在有些情况下势必会用到多继承
在这种情况下java提供了接口的概念,类不能继承多个类,但可以实现多个接口,用曲线救国的方式实现了多继承
参考与借鉴:
https://www.cnblogs.com/dolphin0520/p/3803432.html
https://www.cnblogs.com/qing-gee/p/10077215.html
https://www.cnblogs.com/whitewolf/archive/2010/05/03/1726519.html