Day12
- 多态
1.1 相关知识
- JVM特性 : 多线程,跨平台,面向对象,自动垃圾回收机制
- 面向对象特性 : 封装性,继承性,动态性(多态),抽象
- 多态相关知识点 :
-
软件设计六大原则
-
里氏替换原则 : 能够使用父类的地方就一定可以使用子类
-
1 单一职责原则 : 功能职责单一,只拥抱一种变化
-
2 里氏替换原则 : 所有在使用父类的情况下,都可以使用子类
-
3 依赖倒置原则 : 高层通过抽象依赖底层,
-
4 接口隔离原则 : 不应该依赖于它不需要的接口
-
5 迪米特原则 : 最少知识原则
-
6 开闭原则 : 对扩展开放,对修改关闭
http://baijiahao.baidu.com/s?id=1645013441658118287&wfr=spider&for=pc
1.2 是什么
-
多态就是里氏替换原则的一种体现
-
什么是多态 : 父类引用 指向 子类对象
-
父类引用 : 父类型声明的引用类型变量
-
指向 : 就是通过这个引用类型的变量可以找到谁
-
子类对象 : new 的子类对象
-
通过父类创建一个引用类型的变量,可以找到子类的对象
-
父类 变量 = new 子类();
-
Animal a = new Cat();
-
变量声明 :
-
数据类型 变量名 = 值;
-
变量分类 :
-
局部变量
-
1 方法内部声明
-
2 参数列表声明
-
静态变量
-
成员变量
-
有变量的地方 就可以发生多态,并且多态是发生在赋值的时候
-
Animal a = new Cat();
-
多态发生的几种形式
-
1 直接多态
-
不管成员变量还是局部变量 直接声明式多态 父类 变量 = new 子类();
-
2 形参和实参
-
方法参数定义时 使用父类定义,调用方法时,传递子类对象
-
3 返回值
-
返回值类型定义为父类, 返回数据的时候返回子类对象
-
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210117192349854.png)
-
多态的缺点 : 丢失子类特有的属性
-
多态调用属性 :
-
1 如果调用的是父类没有的,直接报错,都访问不了
-
2 如果调用的是子类没有的,都访问父类的
-
3 如果调用的是父类和子类都有的,那么除了成员方法调用子类的之外,其他的都调用父类的,因为成员方法可以覆写
-
多态得到前提条件
-
1 必须有继承关系的体系中(父,子,爷,孙 都可以)
-
2 多态又叫向上转型
1.3 怎么用
1.4 为什么这么用(优点)
把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
1.5 缺点(扩展)
丢失 子类特有的属性
为什么?
- 多态缺点 丢失子类特有的属性,特有属性需要向下转型后 再进行访问
- 并且 是编译时异常
- 程序从开发到运行的完成生命周期
-
编译阶段 : 在编译阶段的时候,父类文件有,子类文件也有,子类对象没有,但是我们在代码中已经定义了多态
-
这个时候,编译器会直接按照父类类型来划分空,来说明空间中有啥,来检查语法结构
-
这个时候 只能找到父类里面的属性说明,因为空间是父类声明的
-
什么时候有的子类对象? 运行时
-
运行阶段
-
各个类载入方法区,开始运行,执行new 创建对象,对象用子类Cat创建的,所以 对象中是包含子类 特有属性的
-
但是引用变量的类型是父类类型,并且在编译时就已经进行了静态绑定,所以 使用这个父类声明的空间的时候就只能找到父类中有的
-
而 子类对象中 有的特有属性 是没有办法通过父类的变量找到的
-
因为 父类的变量声明的时候 只能够说明父类的属性列表,而创建对象之后,使用子类声明的属性值列表
-
按说 创建了对象,对象中有子类属性,为什么找不到? 因为在编译时就报错了,语句不通过,压根等不到运行时
- 等于 使用父类的属性列表去调用 子类的属性值列表 是找不到
- 编译时 :
-
在编译的时候,会把父类的属性生成一个属性列表,父类属性有了,这叫编译时绑定,绑定完之后,程序就有了,属性就已经固定了
-
属性值没有固定(都没有运行,没有空间,哪来的值?)
-
这种编译时绑定,又可以叫做静态绑定/前绑定
- 运行时 :
-
运行的时候,把类生成对应的对象,也有了子类的属性列表,因为创建了对象,有了空间.进行了初始化操作,所以属性的值也就有了
-
这种在运行阶段进行的数据绑定叫运行时绑定/动态绑定/后绑定
- 调用时 :
-
使用父类的引用,调用子类对象的属性的时候(特有的就访问不到了)
-
也可以理解为 使用父类的属性列表 去调用子类的属性值列表
-
所以问题就出现了,这样子类特有的就没有办法找到了
因为 使用的是父类的属性列表进行调用匹配,所以在找不到的时候语法就不通过了,所以在编译时就会报错,压根不能运行,不运行就没有对象,没有对象就更别提能不能找到特有数据了
*
- super : 官方说法是 代表了父类型特征,这里就可以理解为父类的属性列表
- 使用多态调用结果
-
1 父类没有的,不管子类有没有 都调用不了,直接报错
-
2 只要父类有的,子类没有的,都执行父类的
-
3 父类和子类都有的时候,除了成员方法调用子类,其他都执行父类
-
3 父类和子类都有的时候,除了成员方法调用子类,其他都执行父类
-
3 父类和子类都有的时候,除了成员方法调用子类,其他都执行父类
-
3 父类和子类都有的时候,除了成员方法调用子类,其他都执行父类
1.6 隐式多态(扩展)
* this : 谁调用,this就是谁 所以 这里this 一定是 subClass 这个子类对象
*
* this 是保存当前对象的内存地址,并且是第一个成员变量,既然是变量,那么总得有数据类型吧?
*
* this 用来存储当前对象的内存地址,那么 this的数据类型为 什么的时候 可以存储当前对象内存地址?
* 1 当前类类型
* 2 父类类型
* 如果是父类类型的话,就是多态,父类引用指向子类对象,缺点就是不能调用子类特有的属性,而 this 是可以调用当前类的特有属性的
* 所以 this的类型 是 当前类 类型
*
* 什么是当前类? : 当前类 就是 this所在的类(在哪个类出现的 ,哪个就是当前类)
*
* 那么 这里的this 就等于是 SupClass this
*
* 那么 this的引用 是子类对象,再结合this 是当前类类型 所以成了这样 SupClass this = new SubClass();
1.7 注意
以上这种,在第一行 p下面报错,一般是因为有类名冲突
可以检查一下 是否 存在 一个java文件中 创建了多个 class 并且有class同名
导包出错,傻眼了吧,因为当前包下,有一个和导入同名的类,就会出现这种问题
可以使用类全名解决
建议 不要和已有类同名,尤其是系统类
- Instanceof
- 多态又叫向上转型,可以看做自动类型转换,从子类到父类
- 向下转型,可以看做强制类型转换,从父类到子类,必须先发生向上转型
- instanceof 判断该对象是否有某个类实例化而来
可以避免
- Abstract
3.1 抽象概述
抽象类往往用来表示设计中得出的抽象概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象。
比如:动物,它只是一个抽象的概念,并没有一个 “东西”叫做 “动物”。所以,它并不能代表一个实体,这种情况下,我们就适合把它定义成抽象类。
-
abstract 是修饰符
-
使用abstract 修饰的类,是抽象类
-
使用abstract 修饰的方法,是抽象方法,抽象方法没有方法体,只有功能 定义,没有功能实现,用于让子类实现
-
实现抽象方法,就是给抽象方法加上方法体,去掉abstract修饰
-
抽象类的目的 : 该类不能被实例化对象,只能被继承
-
抽象方法一定在抽象类 中,成立
-
抽象类中一定有抽象方法,不成立,也可以没有,如果就想让某个类不能创建对象,也可以把该类创建类抽象类
-
final修饰的类不能被继承,
-
final修饰的成员方法不能被覆写
-
而 抽象类 就是用于被继承的,抽象方法就是用于被实现覆写的
-
所以 final 和 abstract 不能同时出现
-
一个类 如果要继承一个抽象类,必须要实现该类的所有抽象方法
-
一个抽象类 如果要继承一个抽象类 可以实现 0~N个抽象方法
3.2 怎么用
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210117192622223.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L1l6ajEyMzQ1NjEyNQ==,size_16,color_FFFFFF,t_70)
3.3 注意
- Interface
4.1 是什么
-
引用数据类型 : 类 数组 接口
-
接口是一种引用数据类型,可以看做是一种特殊的类,是java为了解决没有多继承引起的功能变弱的问题
-
一个类只能有一个父类,但是可以实现N个接口
-
创建接口的方式 由 class 变成了 interface 而 父子关系 用 extends 变成了 implements
-
类和类 使用extends,并且单继承
-
类和接口 使用 implements 多实现 多个以逗号隔开,比如 class A implements V,C,D
-
并且 非抽象类实现接口后,必须实现所有的抽象方法
-
抽象类实现接口后 可以实现 0~N个抽象方法
-
接口和接口 使用 extends,并且是多继承 比如 interface A extends B,C,D
-
语法 :
-
public interface 接口名{
-
}
-
1 接口中 所有的变量 默认都是 public static final 的 也就是常量 ,而且 public static final 可以省略
-
2 接口中的方法 默认都是 public abstract 的 也就是抽象方法,而且 public abstract 可以省略
-
3 接口中没有构造方法,不能被实例化对象
-
从 java1.8开始 接口中 可以有 默认方法和 静态方法
-
接口可以看做是一个特殊的抽象类,所以很多时候 接口和抽象类都能做到某一件事
-
优先使用接口,因为 类和接口之间是多实现, 当使用接口之后,还可以保留类的继承
4.2 怎么用
4.3 接口和抽象类