📖1.0 什么是继承
继承是面向对象的一个重要特性,它允许一个类(子类)继承另一个类(父类)的属性和方法。
子类可以继承父类的公共成员变量和方法,并且还可以重写父类的方法或者新增自己的成员变量和方法。
继承的主要目的是实现代码的复用和拓展。通过继承,子类可以从父类继承已有的属性和方法,避免了重复编写相同的代码。子类可以在继承的基础上进行功能的扩展,添加自己的特有属性和方法,实现更多的功能。
在 Java 中,使用关键字 extends 来实现类的继承关系,子类继承父类的语法格式如下:
public class 子类名 extends 父类名 {
// 子类的成员变量和方法
}
通过继承,子类可以访问父类中的公共成员变量和方法,包括继承过来的和父类中定义的。
继承的特点:
- 子类继承了父类的特征,可以获得父类的属性和方法。
- 子类可以重写父类的方法,实现自己特有的行为。
- 子类可以添加自己的成员变量和方法。
- 子类可以直接访问父类的非私有成员。
- 子类与父类之间的继承关系是单向的,父类无法继承子类的属性和方法。
- Java 中不支持多重继承,即 一个类只能继承一个父类。
静态的不会被继承,因为静态的不属于对象!!!
继承主要解决的问题:
共性的抽取,实现代码复用!
📖1.1 父类成员访问
1.1.1子类中访问父类的成员变量
在子类方法中 或者 通过子类对象访问成员时:
- 如果访问的成员变量子类中有,优先访问自己的成员变量。
- 如果访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错。
- 如果访问的成员变量与父类中成员变量同名,则优先访问自己的。
成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。
如果子类自己有父类也有,一定要访问父类里面的,那么就要用到另一个关键字 super
1.1.2子类中访问父类的成员方法
1.成员方法名字不同
class Base{
public void methodA(){
System.out.println("Base中的methodA()");
}
}
class Derived extends Base{
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodB(); //访问子类自己的B()
methodA(); //访问父类继承的的A()
// methodD(); //编译失败,在整个继承系统中没有发现方法D()
}
}
总结:成员方法没有同名时,在子类方法中或者通过子类对象访问方法时,则优先访问自己的,自己没有时再到父类中找,如果父类中也没有则报错。
2. 成员方法名字相同
class Base{
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
class Derived extends Base{
public void methodA(int a){
System.out.println("Derived中的methodA(int)方法");
}
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodA(); //没有传参,访问父类中的A()
methodA(20); //传递int参数,访问子类中的A(int)
methodB(); //直接访问,则永远访问到的都是子类中的B(),父类的无法访问到
}
}
问题:如果子类中存在与父类中相同的成员时,那如何在子类中访问父类相同名称的成员呢?
比如这里我要访问父类的 B() 方法?
📖1.2 super 关键字!!!
答:Java 提供了super关键字,该关键字主要作用:在子类方法中访问父类的成员
有些书上会说 他代表父类对象的引用 -->> 这种说法是错的!!!
严格来说:super 就是一个关键字!!! 只是提高代码的可读性!让别人看到这样访问就知道是访问父类的关键字!!!
如图:
- this 访问的时候 不仅可以访问父类,也可以访问子类
- 当时使用 this 访问父类 和 子类 的成员变量的时候, 子类优先访问
- super 只能访问从父类继承过来的成员变量
也可理解为:
- this -->> 先在子类找,子类没有 去父类找,父类也没有 编译报错!!!
- super -->> 直接到父类中找!
【注意】
- super只能在非静态方法中使用(和 this 一样,只能在非静态 成员方法/变量 中使用)
- 在子类方法中,访问父类的成员和方法
- super 在当前类当中 使用 那么 当前类 一定是子类! ! !
super.data 访问父类的成员变量
super.func() 访问父类的成员方法
super() 调用父类的构造方法
总结:
1. 什么是继承? 对共性进行抽取
2. 为什么要继承? 达到代码的复用
3. 子类继承了父类的什么?
📖1.3 子类构造方法
当子类继承父类之后,一定要先帮助父类 (只能在子类当中调用父类的构造方法) 进行构造,然后再构造子类自己!!!
【注意】
- 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用父类构造方法;
- 如果父类构造方法是带有参数的,此时需要用户为子类显示定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
- 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
- super(...)只能在子类构造方法中出现一次,并且不能和this同时出现
在调用构造方法时,super 和 this 不能同时存在。因为他俩都只能在第一行!
📖1.4 super 和 this
【相同点】
- 都是Java中的关键字
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
【不同点】
- this 是当前对象的引用,当前对象即调用实例方法的对象,super 相当于是子类对象中从父类继承下来部分成员的引用
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
- 在构造方法中:this(...)用于调用本类构造方法,super(...) 用于调用父类构造方法,两种调用不能同时在构造方法中出现
- 构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...) 用户不写则没有
📖1.5 初始化 & 代码块的实行顺序
- 静态代码块先执行,并且只执行一次,在类的加载阶段执行
- 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行
📖1.6 protected 关键字
在类和对象中,为了实现封装的特性,Java中引入了访问限定符,主要限定:类或者类中成员能否在类外或者其他包中被访问
📖1.7 继承方式
🌰单继承:
public class A {
······
}
public class B extends A{
······
}
🌰多层继承
public class A {
······
}
public class B extends A{
······
}
public class C extends B{
······
}
🌰不同类继承同一个类
public class A {
······
}
public class B extends A{
······
}
public class C extends A{
······
}
🌰多继承(不支持,错的!!!)
如果需要实现类似这种多继承的关系,后面会讲到 "接口" ,接口就是为了解决多继承问题!
public class A {
······
}
public class B {
······
}
public class C extends A,B{
······
}// Java 不支持多继承
【注意】Java中不支持多继承
一般我们不希望出现超过三层的继承关系
- 如果想从语法上进行限制继承,就可以使用 final 关键字
public final class Test { //密封类 ······ } //此时这个类 将不能被继承
📖1.8 final
- final修饰类时,该类变为密封类,此时这个类 将不能被继承
- final修饰变量时,变量就会变成常量
- final 修饰数组 对象zu
- 我们平时使用的String 字符串类,就是用 final 修饰的,不能被继承
- final 修饰方法 :表示该方法不能被重写
📖1.9 继承与组合
- 继承表示对象之间是 is-a 的关系,比如:狗是动物,猫是动物
- 组合表示对象之间是 has-a 的关系,比如:汽车。
组合 是 has a 或 a part of (一部分)
组合 其实就是代码的实现方式,看着像而已,无继承那样的语法
class Student{
}
class Teacher{
}
class School{
public Student[] students;
public Teacher[] teachers;
public School() {
this.students = new Student[10];
this.teachers = new Teacher[10];
}
}
组合和继承都可以实现代码复用,应该使用继承还是组合,需要根据引用场景来选择,一般建议:能用组合尽量用组合。