Java 继承
一、继承
1、继承的概念
继承是面向对象编程技术的基石,是一种由已有的类创建新类的机制。
类的继承性是子类(subclass)可以从父类自动继承其全部属性和方法的能力。
子类继承父类的属性与方法,就如同在子类中直接声明一样,可以被子类中声明的任何实例方法所调用。
Java不支持多重继承,一个子类只有一个父类。
继承关系也称为泛化关系,描述父类与子类的关系,UML中用带空心三角形的直线表示。
2、子类
创建子类:extends superclass语句指明所要继承的父类。
需要清楚的是,Java中Object类是所有类的父类,它的方法可以被所有类调用。(即默认添加extends Object)
子类自动从父类继承的是public、protected修饰的属性和方法,但是无法访问private修饰的属性和方法。
不管父类在哪个包中,子类继承父类所有的public、protected成员。(这里要分清“继承”和“访问”的概念,参考下面的表格)
对于default访问权限(无访问修饰符),若子类父类位于同一包中,子类可以(自动)继承父类缺省成员;若不是,不会继承。
3、子类能做的事
- 子类可以直接使用继承来的成员变量,就像使用自己定义的变量;
- 声明新的成员变量,若名字和父类的成员变量相同,就会隐藏父类的成员变量;
- 继承而来的方法也能直接使用
- 在子类中实现一个签名与父类方法一样的方法,则会覆盖父类的方法;
- 子类的构造方法可以使用super调用父类的构造方法;
4、构造方法与子类的内存结构
类的构造方法不能拥有修饰符、返回类型和异常声明子句。
子类的构造方法被调用时,首先调用父类的构造方法,然后执行实例变量和静态变量的初始化块,最后才执行子类自己的构造方法。
5、关于父类构造方法的调用
如果子类的构造方法没有显示调用父类的构造方法,那么编译器会自动为它加上一个默认的super()方法调用。但是,如果父类又没有默认的无参构造方法,编译器就会报错,编译器会报错。
而且,super()语句必须是子类构造方法的第一个子句。
6、实例变量初始化器,{...}语句块
除了构造方法外,使用这个“实例变量初始化器”初始化对象的属性!
它会在类的构造方法被调用时运行,运行于父类的构造器之后,当前类的构造方法之前。
7、类变量初始化器 static{...}
初始化类变量,也就是静态代码块,只能初始化一次!(会最早被执行)
8、子类的内存分配
Java中内存被分为堆(heap)、栈(stack)、全局数据区和代码区。
new出来的对象都放在堆里,它的使用通过引用来调用它。
引用被压入栈里(因为引用很小,适合在栈里进进出出)。
实际上,从内存的角度看,子类会拥有父类的所有属性(即包括private),但是子类的对象并不能直接访问父类中的私有变量,这也是类封装的关键。
二、Java中的修饰符
按被修饰的对象:类修饰符、属性修饰符、方法修饰符
按功能:
1、访问权限修饰符
public、private、protected、default(之前已经介绍)
来自不同包的父类的不同访问修饰符修饰的成员,在子类中的可见性如下表:
作用域 | 当前类 | 同一包内 | 子类 | 其它包 |
public | OK | OK | OK | OK |
protected | OK | OK | OK | X |
default | OK | OK | X | X |
private | OK | X | X | X |
2、final修饰符
final意味着不可变。
修饰类:类不能被扩展,即不能被继承。
修饰属性:属性值不能改变,意味着声明时要手动初始化。
修饰方法:方法不能被重写,即为最终版本,子类不能修改。
3、abstract修饰符
修饰类:该类为抽象类,不能被实例化,必须扩展后才能生成对象。
修饰方法:抽象方法,必须被子类重写(override)。
4、static修饰符
表名属性和方法都隶属于类~可以通过类名访问。
5、super修饰符
super是指向父类的引用,相当于父类的名字,它使被屏蔽的父类成员变量或者成员方法变为可见。
如果子类中,隐藏、覆盖了父类的属性和方法,可以通过super进行调用。
super的使用:
-
- 访问父类的隐藏属性:super.variable
- 调用父类被重写的方法:super.method([paralist])
- 调用父类的构造方法:super([paralist])