1.继承的简介
继承是从已有的类中派生出新的类,新的类拥有已有类的数据属性和行为,并能够扩展新的属性和行为,继承体现的是一种"is a"
的关系(包含关系)
继承中继承者被称为子类,被继承者称为父类,继承应该遵循里氏替换原则(Liskov-Substitution Principle)
多个类中存在相同属性和行为,将这些内容提取到单独的一个类中,那么就多个类无需再定义这些属性和方法,只需要使用继承就可以使用父类的属性和方法
关键字:extends
格式:修饰符 class 子类名 extends 父类名{}
好处:
-
提高代码的复用性
-
提高代码的维护性
-
让类与类之间产生关系,是多态的前提
弊端:
- 增强了类的耦合性(父类改变就会改变所有继承的子类)
开发的原则:
-
低耦合,高内聚
耦合:类与类之间的关系
内聚:自己完成某件事的能力
2. Java中继承的特点
-
只支持单继承不支持多继承(c++就支持多继承)
-
Java支持多层继承(继承体系)
注意事项:
-
子类只能继承父类所有非私有成员(成员方法和成员变量)
-
子类不能继承父类的构造方法,但是可以通过super关键字去访问构造方法
-
不要为了部分功能而去继承。
3. 从类的结构看继承
继承中成员变量的关系:
-
子类中的成员变量和父类的成员变量名称不一样:访问谁就用谁
-
子类中的成员变量和父类的成员变量名称一样:就近原则
在子类方法中访问一个变量的查找顺序:
-
在子类方法的局部范围找,有就使用
-
在子类的成员范围找,有就使用
-
在父类的成员范围找,有就使用
-
如果还找不到就报错。
继承中成员方法的关系:
-
子类中的方法和父类中的方法声明不一样的情况:访问谁就用谁
-
子类中的方法和父类中的方法声明一样的情况:
通过子类调用,如果子类有就调用
如果子类没有找父类的
父类没有就报错
方法重写(Override):子类中出现和父类中方法声明一模一样的方法,方法重写最终调用子类的方法
继承中构造方法的关系:
- 子类的所有构造方法都会默认去访问父类的无参构造方法
原因:因为子类会继承父类的数据,可能还会使用父类的数据,所以子类初始化之前,一定要先完成父类的数据初始化
- 子类不能继承父类的构造方法怎么做呢?
子类每一个构造方法的第一条语句都是super()
(会访问父类的无参构造)
注意事项:
如果父类没有无参构造方法(定义有参,默认无参自动取消),那么子类的构造方法会出现什么现象?
现象:会报错!
解决方法:- 在父类中加一个无参构造器
- 通过使用super关键字显示的调用父类的带参构造
- 子类通过this去调用本类的其他构造方法,其他构造方法内必须有super关键字去调用父类的有参构造。
继承的体现:
//定义学生类
class Student{
int age;
String name;
public Student(){
}
public void eat(){
System.out.println("吃饭");
}
}
//定义老师类
class Teacher{
int age;
String name;
public Teacher(){
}
public void eat(){
System.out.println("吃饭");
}
}
class Person{
String name;
int age;
pubilc Person(){
}
public void eat(){
System.out.println("吃饭");
}
}
//定义学生类
class Student extends Person{
int age;
String name;
public Student(){
}
}
//定义老师类
class Teacher extends Person{
int age;
String name;
public Teacher(){
}
4.Java为什么不支持多继承
在java中只支持单继承,但是在其他面向对象编程语言中有可能支持多继承,为什么Java中偏偏不支持多继承呢?
菱形继承问题
假如类B
和类C
都继承了类A
,另外还有类D
,类D
通过多继承机制继承了类B
和类C
此时类D
会因为多层继承机制,继承两份类A
中的属性和方法(一份来自类B
,一份来自类C
)
此时在使用类D
时,如果想要调用一个定义在类A
中的方法时,就会出现歧义
这就是C++的菱形继承问题,C++为了解决菱形问题,又引入了虚继承
因为支持多继承,导致了菱形继承问题;又因为要解决菱形继承问题,引入了虚继承,但是在实际开发中,需要使用多继承的情况并不多,因此在Java中,不支持多继承;
接口支持多继承,是因为接口只允许方法声明,不允许方法实现,但是在Java8开始支持默认函数后,就不那么绝对了,
Java8解决菱形继承问题制定了如下规则:
-
类中方法优先级最高,类或父类中声明的方法的优先级高于任何声明为默认方法的优先级
-
方法签名相同时,优先选择拥有最具有实现的默认方法的接口(子接口的方法优先级比父接口优先级高)
-
继承多个接口的类必须通过覆盖和调用期望方法,显示指定使用哪一个方法的实现