1、继承的概念:
继承主要解决的问题:共性的抽取,实现代码复用
可以让我们在保持原有类(父类、超类、基类)特性的基础上进行扩展,增加新功能,这样产生新的类,称为派生类(子类)
2、继承的语法:
- Java中表示类之间的继承关系,要用到 extends 关键字
- 子类会将父类中的成员变量或成员方法继承到子类中
- 子类继承父类后,必须要新添加自己特有的成员
3、父类成员访问
3.1 子类访问父类中的成员变量
1、子类和父类中不存在同名成员变量
public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10;//访问从父类中继承下来的a
b = 20;//访问从父类中继承下来的b
c = 30;//访问子类自己的c
}
}
2、子类和父类中存在同名成员变量
public class Base {
int a;
int b;
}
public class Derived extends Base{
int a;//与父类中成员a同名,且类型相同
char b;//与父类中成员b同名,但类型不同
int c;
public void method(){
a = 55;
b = 66;
c = 77;
//d = 40;error
System.out.println(a);
System.out.println(b);
System.out.println(c);
}
public static void main(String[] args) {
Derived d = new Derived();
d.method();
}
}
结果:
分析:
- 如果访问的成员变量子类中有,优先访问自己的成员变量,遵循就近原则
- 如果访问的成员变量子类中没有,则访问父类继承下来的,若父类中也没有定义,则编译报错
- 若个访问的成员变量与父类中成员变量同名,则优先访问自己的
3.2 子类访问父类的成员方法
- 通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找不到就在父类中找,都找不到则编译报错
- 通过子类对象访问父类与子类中同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法所传递的参数选择合适的方法访问,没有则报错
- 想要通过子类对象访问父类与子类中同名的方法,且参数列表也相同时,需用到关键字 super
4、super 关键字
作用:在子类方法中访问父类的成员
示例:
public class Base {
int a;
int b;
public void methodA(){
System.out.println("methodA()::Base");
}
public void methodB(){
System.out.println("methodB()::Base");
}
}
public class Derived extends Base{
int a;//与父类中成员a同名,且类型相同
char b;//与父类中成员b同名,但类型不同
int c;
//与父类methodA()构成重载
public void methodA(int x){
System.out.println("methodA()::Derived");
}
//与父类methodB()构成重写
public void methodB(){
System.out.println("methodB()::Derived");
}
public void method(){
a = 55;
super.b = 66;//访问父类与子类同名成员变量用super
c = 77;
//父类与子类中构成重载的方法,通过参数列表区分访问
methodA();
methodA(c);
//父类与子类中构成重写的方法,需借助super访问父类方法
methodB();
super.methodB();
System.out.println(a);
//访问父类与子类同名成员变量用super
System.out.println(super.b);
System.out.println(c);
}
public static void main(String[] args) {
Derived d = new Derived();
d.method();
}
}
结果:
tips:
- super关键字只能在非静态方法中使用
- 使用 super() 必须在第一行,与 this() 不共存
- super只能指代当前类的父类,不能指代父类的父类
5、子类构造方法
子类对象构造时,需要先调用父类的构造方法,然后执行子类的构造方法
示例:
public class Animal {
static{
System.out.println("static::Animal{ }");
}
{
System.out.println("实例代码块::Animal{ }");
}
public Animal() {
System.out.println("构造方法::Animal()...");
}
}
//==================================
public class Dog extends Animal{
static{
System.out.println("static::Dog{ }");
}
{
System.out.println("实例代码块::Dog{ }");
}
public Dog() {
System.out.println("构造方法::Dog()...");
}
}
//==================================
public class Cat extends Animal{
static{
System.out.println("static::Cat{ }");
}
{
System.out.println("实例代码块::Cat{ }");
}
public Cat() {
System.out.println("构造方法::Cat()...");
}
}
//==================================
public class Test {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
结果:
原理:子类对象中成员是由两部分组成的,父类继承的部分以及子类新增的部分,先有父再有子,所以在构造子类对象时,先调用父类构造,将继承下来的成员构造完整,再调用子类的构造,将新增成员初始化完整。
tips:
- 若父类显式定义无参或默认的构造方法,在子类构造方法第一行默认有隐含的 super() 调用,即调用基类构造方法
- 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败
- 在子类构造方法中,super(...) 调用父类构造时,必须是子类构造函数中第一条语句
- super(...) 只能在子类构造方法中出现一次,并且不能和this同时出现
结论:
- 父类静态代码块优先于子类静态代码块执行,且最早执行
- 父类实例代码块和父类构造方法紧接着执行
- 子类实例代码块和子类构造方法紧接着执行
- 第二次实例化子类对象时,父类和子类的静态代码块都不会再执行
6、super和this的异同
相同点:
- 都是Java关键字
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
不同点:
- this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
- 在构造方法中,this(...) 用于调用本类构造方法,super(...) 用于调用父类构造方法,两种调用不能同时在构造方法中出现
- 构造方法中一定会存在super(...) 的调用,用户没有写编译器也会加,但是this(...) 不写则没有
7、protected关键字
用protected修饰的成员变量不能在 不同包中的非子类 访问
虽然不能直接访问,但是也继承到子类了
8、Java中的继承方式
如图:
tips:
Java中不支持多继承
在应用场景中,尽量不要出现超过三层的继承关系
想要在语法上进行限制,可以使用final关键字,用final修饰的类无法被继承
9、final关键字
final关键字可以用来修饰变量、成员方法以及类
- 1.修饰变量或字段,表示常量,即不能修改
- 2.修饰类,表示此类不能被继承
- 3.修饰方法,表示该方法不能被重写
10、继承与组合
继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物
组合表示对象之间是has-a的关系,比如:汽车的零件有轮胎、发动机、方向盘等等
//轮胎类
class Tire {
//...
}
//发动机类
class Engine {
//...
}
//组合:轮胎、发动机都是汽车的组成部分
class Car {
private Tire tire;//可以复用轮胎类中的属性和方法
public Engine engine;//可以复用发动机类中的属性和方法
}
//继承:奔驰属于汽车中的一类
class Benz extends Car{
//将汽车中包含的轮胎、发动机全部继承下来
}
优缺点对比:
tips:
- 组合比继承更符合 高内聚低耦合 的状态
- 所以在面向对象中有『多用组合、少用继承』或者说『组合优于继承』的观点
- 在同样可行的情况下,建议使用组合