文章目录
多态
多态的概述
什么是多态
字面上讲,多态就是某一个事物,在不同时刻表现出来的不同状态。
当我们多个子类继承一个父类时,使父类引用指向子类对象(父类 对象名=new 子类()
),就是多态的形式。
多态的前提
- 要有继承关系。
- 要有方法重写。 其实没有也是可以的,但是如果没有这个就没有意义。
子类需要对父类方法进行重写,多态就是为了通过调取父类类型的对象既可完成子类特有功能,若子类无方法重写,我们直接调取子类对象即可,失去了多态的意义。 - 要有父类引用指向子类对象。
父 f = new 子();
多态的优势与劣势
- 优势
比如我们需要对几种不同的动物饮食习惯进行描述,那么这些不同的动物有公共的属性与功能,为了同时体现出他们独有的功能属性,继承是必不可少的。
- 现在我们定义猫、狗和老虎(三个类继承于动物父类):
- 在不使用多态时,我们添加Set类来调用eat:
- 测试这三种动物的饮食习惯
- 但是如果现在出现了一个新的物种猫狗兽CatDog,我们需要新增加一个子类Catdog:
但是在增加子类的同时我们的Set类中也需要添加对CatDog类中eat方法的调用,如果在增添大量的子类,我们会发现Set类需要不断的修改:
会发现过程会变得十分的繁琐,是代码毫无扩展性。所以我们引入多态的形式
这样就变得简单了许多,并且增添新的子类是无需修改Set类。提高了代码的扩展性,降低了类之间的耦合性。
- 弊端
多态无法调用子类特有的方法
当我们用父类引用创建子类对象时,通过父类调用子类特有方法会出现类型转换异常:
这时我们需要向下转型(多态就是向上转型),将父引用转成他所指向的那个子类型:
多态中的成员访问特点
我们创建一个父类一个子类,子类继承与父类,其中都有各自的成员变量,构造方法,静态方法,并且子类重写了父类的成员方法,我们通过多态的形式创建子类对象。
构造方法
创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。
成员变量
- 多态的形式去访问成员变量,访问的还是父类的成员变量
- 编译看左边,运行看左边
成员方法
- 多态的形式去调用方法时,调用的是子类改写后的成员方法。
- 编译看左边,运行看右边
静态方法
- 引为静态方法内存中存在于方法区,可通过类名直接调用,所以静态方法不算重写,通过子类对象调用的依然是父类的静态方法,想调用子类的静态方法直接通过子类名访问。
- 编译看左边,运行看左边
抽象类
回想前面我们的猫狗案例,提取出了一个动物类。并且我们也创建过了动物对象,其实这是不对的。
因为我们给动物定义具体的功能属性本来就是不合理的,动物是一个抽象的事物,并不是一个具体的事物,所以我们不应该给动物定义具体的属性和功能,之给出一个声明即可,具体的功能应该在具体的猫狗等等中具体定义。
抽象类概述
什么是抽象类
- 在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
抽象类特点
- 我们依然拿描述动物和猫举例
- 抽象类和抽象方法必须用abstract关键字修饰
抽象类格式:abstract class 类名 {}
抽象方法格式:public abstract void eat();
- 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
- 当一个类,继承了一个抽象类,那么这个抽象类中的所有抽象方法,子类必须重写
- 抽象类中可以有构造方法,抽象类不能进行实例化,那么要构造方法有什么作用呢?
用于子类访问父类数据时的初始化
抽象类不能直接实例化那么,抽象类如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
- 抽象类的子类:要么是抽象类,要么重写抽象类中的所有抽象方法
抽象类的成员特点
- :成员变量:既可以是变量,也可以是常量。
- 构造方法:有
用于子类访问父类数据的初始化。 - 成员方法:既可以是抽象的,也可以是非抽象的。
- 抽象类的成员方法有什么特性呢?
- 抽象方法:强制要求子类做的事情。
- 非抽象方法:由子类继承,提高代码复用性。
接口
继续回想我们的猫狗案例,当我们已经定义过了猫和够的属性与功能,有一天突然发现我们的猫学会了抓老鼠,狗学会了看门,我们去在子类中添加这些功能会十分麻烦,也不合适,因为不是所有的猫和狗都学会了额外的本领。
所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗具备了这种特性,只需要这部分猫狗把这些额外功能实现即可。
接口的特点
- 接口用关键字interface表示 格式:
interface 接口名 {}
接口中定义的是抽象方法
- 类实现接口用implements表示 格式:
class 类名 implements 接口名 {}
实现接口的子类必须对接口中方法进行重写
- 接口不能实例化那么,接口如何实例化呢?
按照多态的方式来实例化。
- 接口的子类:
- 可以是抽象类。但是意义不大。
- 可以是具体类。要重写接口中的所有抽象方法。
接口的成员特点
- 成员变量:只能是常量,并且是静态的。
默认修饰符:public static final
建议:自己手动给出。
- 构造方法:接口没有构造方法。
- 成员方法:只能是抽象方法。
默认修饰符:public abstract
建议:自己手动给出。
- JDK1.8之后在接口中提供了用default修饰的方法,可以给出功能的具体实现,子类可以继承下去用
类、抽象类、 接口之间的关系
类与接口的关系
- 类与类:
继承关系,只能单继承,可以多层继承。 - 类与接口:
实现关系,可以单实现,也可以多实现。
并且还可以在继承一个类的同时实现多个接口。
这说明接口的引入弥补了继承关系中无法多继承的缺陷
- 接口与接口:
继承关系,可以单继承,也可以多继承。
抽象类和接口的区别
成员区别
- 抽象类
成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象,也可以非抽象 - 接口:
成员变量:只可以常量
成员方法:只可以抽象
关系区别
- 类与类
继承,单继承 - 类与接口
实现,单实现,多实现 - 接口与接口
继承,单继承,多继承
设计理念区别
- 抽象类
被继承体现的是:”is a”的关系。 抽象类中定义的是该继承体系的共性功能。 - 接口
被实现体现的是:”like a”的关系。 接口中定义的是该继承体系的扩展功能。