继承
为什么要有继承?
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中, 那么多个类无需再定义这些属性和行为,只要继承那个类即可。
继承性的好处
- 减少了代码的冗余,提高了代码的复用性;
- 便于功能的扩展;
- 为之后多态性的使用,提供了前提。
继承性的格式
class A extends B{}
//A:子类、派生类、subclass
//B:父类、超类、基类、superclass
体现:一旦子类 A 继承父类以后,子类 A 中就获取了父类 B 中声明的结构:属性、方法。特别的,父类中声明为 private 的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只有因为封装性的影响,使得子类不能直接调用父类的结构而已。
继承性的规定
- 一个类可以被多个子类继承
- 一个类只能有一个父类
- 子父类是相对的概念
- 如果我们没有显示的声明一个类的父类的话,则此类继承于java.lang.Object类。
class SubDemo extends Demo{} ✅
class SubDemo extends Demo,Demo2{} ❌
protected关键字
父类中protected关键字修饰的属性与方法,可以在不同包的子类中被访问。具体参见修饰权限的那节。
super
super调用属性与方法
子类中重写了父类的方法,但是在子类中也要用到父类的方法,可以用super关键字来使用父类中的方法。
- 我们可以在子类的方法或构造器中,通过"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯去省略这个"super."前提是子类中的没有与父类同名的属性。
- 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。实际中也不会/不应该出现与父类同名的属性。
- 特殊情况:当子类重写了父类中的方法后,我们想在子类的方法中调用父类中被重写的方法时,必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
super调用构造器
可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器。但是注意:
super(形参列表)的使用,必须声明在子类构造器的首行。- 类的构造器中,针对于
this(形参列表)或super(形参列表)只能二选一,不能同时出现。 - 在构造器的首行,既没有显式的声明"this(形参列表)"或"super(形参列表)",则默认的调用的是父类中的空参构造器。
super() 在类的多个构造器中,至少有一个类的构造器使用了super(形参列表),调用父类中的构造器。- 子类在没有显式的定义构造器的情况下,一定也会隐式的调用父类的构造器
super()。如果父类没有空参的构造器,只有带参的构造器,子类应该显式的调用父类带参的构造器。
子类对象实例化的过程
从结果上看: 子类继承父类以后,就获取了父类中声明的属性或方法。创建子类的对象中,在堆空间中,就会加载所有父类中声明的属性。
从过程上看: 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类构造器,直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类结构,所以才可以看到内存中有父类中的结构,子类对象可以考虑进行调用。
明确:虽然创建子类对象时,调用了父类的构造器,但自始至终就创建过一个对象,即为new的子类对象。