继承多态
1.继承
在多个类中存在相同的属性与行为,通过共性抽取,将相同的内容提取到一个类中,那么其他的类无需再次定义这些属性与行为,只需继承该类,即可获得相同的属性与行为
1.1.定义
- 被继承的类一般被叫做父类,超类或者基类;有继承行为的多个类被称为子类
- 继承:即子类继承父类的属性与行为,使得子类具有与父类相同的属性与行为,子类可以直接访问父类中非私有的属性与行为。从而提高代码的复用性,使得类与类之间产生了关系,是多态的前提。
1.2.格式
- 子类通过
extend
关键字声明继承父类
class 父类 {
...
}
class 子类 extends 父类 {
...
}
1.3.注意事项
1.成员变量
- 子父类成员变量不重名:
各成员变量访问无影响 - 子父类成员变量有重名:
在子类中若要访问父类中非私有成员变量时,需使用super
关键字进行修饰:super.父类成员变量名
从而取得父类成员变量。
2.成员方法
- 子父类成员方法不重名:
各成员变量调用无影响。 - 子父类成员方法有重名:
即子类中出现与父类一样的方法时(返回值类型,方法名与参数列表相同),此时的访问被称为方法重写,子类继承父类的方法声明,子类的方法实现覆盖父类的实现,对方法进行了重写。在实际运用中,子类可以根据需要,定义特定于自己的行为,既继承了父类的功能名称,又根据子类的需要重新实现父类方法,进行拓展增强。
3.构造方法
- 构造方法的名称与类名相同,故子类无法继承父类的构造方法
- 构造方法的作用是初始化成员变量,故在子类的初始化过程中,需要先执行父类的初始化动作,所以在子类的构造方法中默认含有一个
super()
,表示调用父类的构造方法。
4.特点
- Java中只支持单继承,不支持多继承。即一个类只能有1一个父类,不可以有多个父类
class C extends A{} //ok
class C extends A,B... //error
2.抽象类
由子类继承并重写父类中的方法,子类的实现各不相同。故在父类的方法声明与方法主体中,只有声明还存在意义,而方法的主体实现没有意义,实现为空,而没有方法实现主体的方法被称为抽象方法,包含抽象方法的类被称为抽象类。
2.1.标识符
通过使用abstract
关键字修饰方法,该方法被标识为抽象方法,抽象方法中只包含一个方法名,而没有方法体
定义格式:
- 抽象方法
修饰符 abstract 返回值类型 方法名 (参数列表);
例:
public abstract void test();
- 抽象类
abstract class 类名字 {
}
例:
public abstract class Exam {
public abstract void test();
}
2.2.使用方法
继承抽象类的子类必须重写父类的所以抽象方法,否则该子类也必须声明为抽象类,在继承关系的最后,必须有子类实现该父类的抽象方法,否则从最初的父类到最终的子类均无法创建对象。
3.接口
接口是Java语言中的一种引用类型,是方法的集合,类的内部封装了成员变量、构造方法与成员方法;则接口的内部**封装了方法,**包含了抽象方法,默认方法与静态方法,私有方法。
- 接口的定义与类相似,但使用
interface
关键字,仍可以被编译为.class文件,但不是类而是另一种引用数据类型。 - 接口不能创建对象,但可以被实现(
implements
,类似于继承);一个实现接口的类需要实现接口中所有的抽象方法。 - 格式定义:
public interface 接口名称 {
// 抽象方法
public abstract void method() {
//执行语句
}
// 默认方法
public default void method() {
// 执行语句
}
// 静态方法
public static void method2() {
// 执行语句
}
// 私有方法
private void method() {
// 执行语句
}
}
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
静态方法:使用 static 修饰,供接口直接调用。
私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
3.1.基本实现
非抽象子类实现接口:
- 通过
implements
关键字修饰接口的实现类。 - 必须重写接口中的所有抽象方法。
- 接口的默认方法,可以直接继承或者重写,但只能通过实现类的对象来调用
- 接口的静态方法只能通过接口名调用,无法通过实现类类名或实现类对象调用
3.2.多接口实现
一个类可以在继承一个父类的基础上,同时实现多个接口
- 实现:
class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... {
// 重写接口中抽象方法【必须】
// 重写接口中默认方法【不重名时可选】
}
- 多接口的实现中,实现类必须重写所有抽象方法,如果在多个接口中有重名的抽象方法,则只需重写一次。
- 多接口的实现中,实现类可以继承使用各接口中的默认方法,如果在多个接口中存在重名的默认方法,则必须重写一次
- 当子类同时继承父类又实现若干接口时,若父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。
- 子接口可使用
extends
关键字继承若干父接口,若多个父接口中有重名默认方法,则子接口需要重写一次。 - 接口中无法定义成员变量
- 接口中可使用
public static final
修饰定义固定值常量 - 接口中没有构造方法,不能创建对象
- 接口中没有静态代码块
4.多态
- extends继承或implements实现是多态性的前提
- 一个对象具有多种形态,被称为对象的多态性
- 代码体现:父类的引用指向子类对象(创建一个子类对象,作为父类类型使用),
父类名称 对象名 = new 子类名称();
或
接口名称 对象名 = new 实现类名称();
- 多态体现时,以父类类型存在的子类对象可执行被子类重写的方法,以此可创建以父类类型为参数的方法调用,替代若干子类对应重写方法的调用,使得程序编写更加简单,并具有良好的拓展性
假设一个动物类:Animal有猫:cat和狗:dog两个子类,并分别重写父类的eat方法
则多态中:
public class Test {
public static void main(String[] args) {
// 多态形式,创建对象
Cat c = new Cat();
Dog d = new Dog();
// 调用showCatEat
showCatEat(c);
// 调用showDogEat
showDogEat(d);
/*
以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代
而执行效果一致
*/
showAnimalEat(c);
showAnimalEat(d);
}
public static void showCatEat (Cat c){
c.eat();
}
public static void showDogEat (Dog d){
d.eat();
}
public static void showAnimalEat (Animal a){
a.eat();
}
}
4.1.多态的转型
- 使用多态方式调用方法时,首先检查父类中是否含有该方法,含有再寻找子类的重写方法,若父类中无该方法则编译错误。故多态方式无法调用子类特有而父类没有的方法,要想调用子类特有方法必须做向下转型。
- 向上转型:
多态本身是子类类型向父类类型向上转换的过程,过程是默认可完成。 - 格式:
父类类型 变量名 = new 子类类型();
如:Animal a = new Cat();
- 向下转型
父类类型向子类类型向下转换的过程,过程是强制完成的。
只有已向上转型的子类对象,要将父类引用转为子类引用,可以使用强制类型转换的格式。(只有本来就是该子类对象的父类引用才能向下转型为该子类对象,否则会报错) - 格式:
子类类型 变量名 = (子类类型) 父类变量名;
如:Cat c =(Cat) a
当得到的参数为父类类型需要做向下转换时,要考虑到转型的对象是否对应,避免ClassCastException
类型转换异常,必须使用instanceof关键字进行校验
- 格式: 父类 instanceof 某子类
- 判断该父类引用原本是否是该子类对象返回一个boolean
public static void giveMeAPet(Animal animal) {
if(animal instanceof Dog{
Dog dog = (Dog) animal;
dog.watchHouse();
)
if(animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
2020/8/31