继承
为什么需要继承
继承可以解决代码复用,让我们的编程更加靠近人类思维. 当多个类存在相同的属性(变量)和方法时,可以从这些类中 抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过 extends 来声明继承父类即可
语法
class 子类 extends 父类{ }
-
子类就会自动拥有父类定义的属性和方法。
-
父类又叫超类,基类。
-
子类又叫派生类。
继承的好处
-
代码的复用性提高了
-
代码的扩展性和维护性提高了
继承的注意事项
-
子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
-
子类必须调用父类的构造器, 完成父类的初始化
-
当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,即默认有super();如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过
-
如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
-
super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
-
super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
-
Java 所有类都是 Object 类的子类, Object 是所有类的基类.
-
父类构造器的调用不限于直接父类! 将一直往上追溯直到 Object 类(顶级父类)
-
子类在调用父类属性时,会一直往上找,直至找到,中途找到该属性且不可访问,就会停止寻找,并报错
-
-
子类最多只能继承一个父类(指直接继承) ,即Java 中是单继承机制。
-
如何让 A 类继承 B 类和 C 类?
可以让A 继承 B , B 继承 C
-
-
不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关系
-
Cat extends Person x
-
Cat extends Animal √
-
练习题
题目一
class A { A() { System.out.println("a"); } A(String name) { System.out.println(" a name"); } } class B extends A { B() { this(" abc"); System.out.println("b"); } B(String name) { System.out.println("b name"); } }
在main中: B b=new B();会输出什么? 答案: a b name b
题目二
class A {//A 类 public A() { System.out.println("我是 A 类"); } public static void main(String[] args) { C c =new C(); } } class B extends A { //B 类,继承 A 类 public B() { System.out.println("我是 B 类的无参构造"); } public B(String name) { System.out.println(name + "我是 B 类的有参构造"); } } class C extends B {//C 类,继承 B 类 public C() { this("hello"); System.out.println("我是 c 类的无参构造"); } public C(String name) { super("hahaha"); System.out.println("我是 c 类的有参构造"); } }
在main中: C c =new C();会输出什么内容?
答案:我是 A 类 hahaha我是 B 类的有参构造 我是 c 类的有参构造 我是 c 类的无参构造
super关键字
基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器
基本语法
-
访问父类的属性,但不能访问父类的private属性 super.属性名;
-
2.访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
-
访问父类的构造器(这点前面用过): super(参数列表);
-
只能放在构造器的第一句,只能出现一句!
-
注意事项
-
调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化)
-
当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、 直接访问是一样的效果!
-
super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A-> B->C,当然也需要遵守访问权限的相关规则
super 和 this 的比较
No. | 区别点 | this | super |
---|---|---|---|
1 | 访问属性 | 访问本类中的属性,如果本类没有此属性则从父类中继续查找 | 从父类开始查找属性 |
2 | 调用方法 | 访问本类中的方法,如果本类没有此方法则从父类继续查找 | 从父类开始查找方法 |
3 | 调用构造器 | 调用本类构造器,必须放在类构造器的首行 | 调用父类构造器,必须放在子构造器的首行 |
4 | 特殊 | 表示当前对象 | 子类中访问父类对象 |
this访问属性和调用方法
-
先找本类,如果有,则调用
-
如果没有,则找父类(如果有,并可以调用,则调用)(super直接从这里开始)
-
如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到Object类
-
提示:如果查找方法的过程中,找到了,但是不能访问,则报错,cannot access
-
如果查找方法的过程中,没有找到,则提示方法不存在
-
方法重写/覆盖(override)
基本介绍
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法
注意事项
方法重写也叫方法覆盖,需要满足下面的条件
-
子类方法的形参列表,方法名称,要和父类方法的形参列表,方法名称完全一样。
-
子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类。比如父类返回类型是Object ,子类方法返回类型是String
-
子类方法不能缩小父类方法的访问权限 。public > protected >默认> private
方法的重写和重载比较
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|---|---|---|---|---|
重载(overload) | 本类 | 必须一样 | 类型,个数或者顺序至少有一个不同 | 无要求 | 无要求 |
重写(override) | 父子类 | 必须一样 | 相同 | 子类重写的方法,返回的类型和父类的一致,或者是其子类 | 子类方法不能缩小父类方法的访问范围。 |