在 Java 中,一个类继承了另一个类,那么前者就可以使用后者的成员变量或者成员方法了。继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承格式:
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
class 父类 {
}
class 子类 extends 父类 {
}
如果不使用继承的话,我们来看代码:
从这段代码可以看出来,代码存在多处重复的地方,如果有更多的成员变量和方法,那就会存在更多重复的代码,造成代码冗余,后期需要修改的时候,就需要修改大量的代码,容易出错。所以使用继承的方式,将两段代码中相同的部分提取出来作为父类。
在子类方法中或者通过子类对象访问成员时:
访问成员方法时:
在实际开发中,子类和父类中可能会存在相同名称的成员,如果要在子类方法中访问父类同名的成员时,我们可以使用 Java 提供的 super 关键字,该关键字主要作用:在子类方法中访问父类的成员。
注意: 只能在非静态方法中使用。
总之就是,在通过子类访问成员变量或方法时,子类中有,就会优先访问子类中的,子类中没有,才会到父类中访问,如果父类也没有,那就会编译错误。如果想访问父类的成员,那就要加上 super 关键字。
构造子类对象时,需要先调用父类的构造方法,然后再执行子类的构造方法。
那为什么子类构造时要调用父类的构造方法?
这是因为,子类继承父类,所以子类也拥有了父类的公共成员变量,但是,父类的成员变量并没有在子类中声明,所以需要通过父类的构造方法进行初始化。
单继承:也就是 B 继承 A,A 是 B 的父类。
多层继承:C 继承 B,B 继承 A,A 是 B 的父类,B 是 C 的父类。
不同类继承同一个类:C 继承 A,B 继承 A,A 是 B 和 C 的父类。
注意: Java 不支持 C 继承 B,再继承 A 这种多继承关系,只能有一个父类。
final 关键字可以用来修饰变量、方法和类。
当 final 修饰变量的时候,那这个变量就成了常量,不能被修改。
final int a = 5;
a++; 报错
当 final 修饰方法的时候,那这个方法就不能重写(下面有介绍)。
当 final 修饰类的时候,那这个类就不能被继承。
重写就是子类根据自己的特性或情况,对父类允许访问的方法进行重新编写,返回值和形参都不能改变。也就是外壳不变,核心的地方重写。
好处: 子类可以根据需要,定义符合自己的行为,也就是可以根据需要实现父类的方法。
具体案例:
在上面的代码中,b 属于 Father 类,但运行的是 Son 类的 run 方法。这是因为在编译时,只检查参数的类型,不确定方法的行为,在运行的时候,才会根据具体的对象调用方法。
再来一个案例:
上面的代码中,执行了 hungry 方法,但是 b 的类型是 Father,而 Father 类里并没有 hungry 方法,所以会报错。所以,当父类申明的变量指向了子类实例,父类变量不能调用父类里不存在的变量或方法,否则编译报错。
重写: 可以根据相同的材料,做出不同的菜。
重载: 根据不同的材料(材料的顺序,种类,个数都算),做出相同或不同的菜。
多态,用大白话说就是有多种转态,同个行为有多个不同的表现形式,使用不同的实例就可以执行不同的操作。
就像打印机,使用黑白的打印机就只能打印出黑白的,使用彩印的就可以打印出来彩色的。
实现多态,需要满足以下几个条件:
下面这段代码就能体现出多态:
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
向上转型 其实就是创建一个子类对象,将其当成父类对象来使用。
格式:父类类型 对象名 = new 子类类型( )。例如上面的 Father b = new Son( );
优点:让代码实现更简单灵活。
缺点:不能调用到子类特有的方法。
使用场景:直接赋值、方法传参、方法返回。
向下转型 将一个子类对象经过向上转型之后当成父类方法使用,无法调用子类的方法,但有时候需要调用子类特有的方法,此时:将父类引用再还原为子类对象即可,即向下转换。
例如:Father b = new Son( ); Son s = (Son)b;
Java中为了提高向下转型的安全性,引入了 instanceof ,如果该表达式为 true,则可以安全转换。