目录
一、继承
1. 简介
2. 表现形式
2.1. 电脑的表现形式
2.2. 程序的表现形式
资料库
课程
课程放入到资料库
视频资源
资源库
存在问题
如何解决问题
3. 继承
定义父类
课程类继承
视频类继承item
资源库类2
整个的继承关系
4. 通过继承得到了什么?
5. 访问修饰符
6. super关键词
视频信息类
课程类
资料库
7. 如果子类和父类有相同的属性怎么办?
8. 继承的总结和好处
二、多态
1. 什么是多态
2. 向上转型注意的事项
3. 向上转型总结
4. 函数的绑定
5. 覆盖override
三、Java类&抽象类&接口&枚举
1. 类
1.1. 对象管辖的范围
1.2. 类管辖的范围
证明观点:什么是类的模板,类的信息是如何在内存空间中进行存储的呢?
1.3. 构造方法
1.4. 创建对象
2. 抽象类
2.1 为什么会存在抽象类呢?
2.2 抽象类可以继承抽象类吗?
2.3 疑虑,抽象类可以new吗?
2.4 抽象类化有构造函数,抽象类存在的构造函数的意义是什么?
2.5 抽象类可以继承普通类吗?
2.6 抽象类可以继承抽象类吗?
2.7 抽象类A 继承 抽象类B B的抽象方法,A一定覆盖吗?
2.8 总结
3. 接口
3.1 JDK类的继承存在的问题
3.2 接口的定义
3.3 默认方法
3.4 静态方法
3.5 接口是可以多继承接口的
3.6 Java为什么要存在接口?
4. 接口和抽象类的区别
5. 枚举
用法一:常量
用法二:switch
用法三:向枚举中添加新方法
用法四:覆盖枚举的方法
用法五:实现接口
用法六:使用接口组织枚举
用法七:关于枚举集合的使用
总结
6. 枚举的实际应用场景
HttpStatus
我每天面对是计算机,从学习java语言开始,开始都jdk开始,配置JDK环境变量,然后Hellworld。
然后进行一系列语法的数据,数据类型,循环,判断,运算,类,继承,接口,集合,Map,
io。。。。。。。。。
所有的语言的开发流程,运行流程以及执行流程其实都一样,如下:
总的来说,如下:
- 不同计算语言,虽然有不同语法结构或者语法糖,但是他们开发流程,以及运行流程其实一样的。
- 计算机语言,它是一种人机交互和沟通的一种语言,既然是语言就必须有对应的语法和数据结构,语态等等。
- 就好比,计算语言它是人和机器沟通桥梁。我们底层计算机存储的0|1。计算机语言其实就把现实的一些逻辑转换成计算机可以识别的0|1代码。一句话:java、go 语言等等都在应用程序中的代码转换成0|1和计算机沟通协作。
我们知道,电脑中记事本。记事本比较简单可以记录一句话也可以记录一段文字。但是如果我们想做一
个资料库。
比如这个资料库去保存我们学习的课程视频、课程笔记、课程的相关文件等。
我们会把每一个课程的相关信息的情况放入到这个资料库中。
然后把所以的课程资料通过资料库罗列出来。下面如何通过电脑表现出来呢?又如何通过程序表现出来
呢?
2.1. 电脑的表现形式
2.2. 程序的表现形式
对于资料库中的课程来说,程序的表现应该又如下一些东西
接下来我们花一点点时间,把这两个类,资料库和课程做出来,如下:
资料库
DataBase.java
课程
课程放入到资料库
如何把课程放入到资料库中呢?如下:
打印结果如下:
视频资源
如果要进行扩展需要增加:视频资源
资源库
存在问题
上面代码存在什么问题?
这个时候会发现,课程和视频资源的差异,课程的视频大部分的属性情况下两者是相同。
如何解决问题
我们是否可以把公共的东西进行抽离呢?答案是可以的,实现步骤如下:
1:先抽离放入公共类
2:然后让两者进行实现extends即可。
通过继承我们可以把父类中公开的和受保护方法和属性进行让子类进行共享使用。
从而达到复用的目的。
定义父类
Item.java
课程类继承
视频类继承item
资源库类2
整个的继承关系
那就看父类有什么?父类也是一个类:类里面也就只有属性和方法。得到也就是父类所有的属性和方
法,但是如果子类中有和父类相同的方法和签名的时候,就会引发重写(覆盖),如果我们要明确的是
覆盖的方法可以通过 @Override 关键词标识出来。
子类是不是可以获取父类所有的方法和属性呢?当然不能因为牵涉到一个问题就是:访问权限。
子类可以获取父类中的什么样子的属性和方法呢?如下:
- 公开的 public
- 受保护的 proctected
-
- 如果在开发中,一个父类想让子类去获取成员属性和方法的话,尽量定义成protected
- 如果父类的成员属性和方法私有的,就可以通过公开get方法进行获取私有属性,
- 如果要给父类的私有属性要初始化或者赋值。你可以通过super方法进行给私有属性赋值,或者公开的set方法
- 缺省的(default) (同包中 )
子类是不是可以获取父类所有的方法和属性呢?当然不能因为牵涉到一个问题就是:访问权限。
- 子类不能访问父类私有的成员和属性
- 一般父类定义属性的时候,如果要让其子类共享属性,一般设置为proctected,这样更好!
- 一般父类定义属性的时候,如果要让其子类共享属性,如果设置成private,可以通过super方法进行传递给父类。
- 子类覆盖父类的方法的时候访问权限必须大于父类方法本身的访问权限
子类集成父类的时候,每个子类的构造函数都有一个隐式的super调用,可以暴露出来。
也可以不暴露出来。而这个super方法默认指向父类的构造函数。
- 每个子类继承父类以后,每个子类的都会有一个默认的隐式super()方法
- 如果一个类没有继承父类,它父类就是Object,这个时候super()方法执行的就是Object的构造功函数
- 这个super()方法的作用,其实大部分的作用:就给父类的私有成员变量进行赋值使用。
- 但是如果父类的无参构造函数一旦被定义成有参数的,子类构造函数的super()方法就必须显示的声明。如果不什么编译不通过。
视频信息类
课程类
资料库
相同的属性,相互隔离互不影响
- 父类除了能够很好的把一些公共的方法和属性进行封装,让其子类继承达到复用以外。
- 继承还有一个很重要的意义:就是分担职责
- 继承可以达到:复用、封装、职责分担的作用。
从上面可以得出结论:
- Java中的任何一个类都是多态的,它们能保存不止一种类型的对象。
- 它们可以保存的是除了自身对象以外,还可以保存声明类型的子类的对象。
- 当把子类对象赋值给父类对象的引用的时候,就会引发多态。(也称之为:向上造型)。
子类的对象可以赋值给父类的变量,就会引发向上造型cast
注意:Java中不存在对象对对象分覆盖和赋值操作。
比如:
这个时候在内存空间中,是两个内存地址,而不是一个,
首先会在内存空间中开辟一个空间,才能空间存储abc,让str指向,然后在开辟一块内存空间地址存储:“bcd” 。
让其str指向新的地址,原来的地址在jvm中也就是:垃圾内存。
父类的引用对象不能直接赋值给子类的变量
可以使用强制类型转换(造型)
- 用括号围起来的类型放在值的前面(只限于对象类型)
- 对象本身并诶呦发生任何变化,所以不是“类型转换”
- 运行时如果不合理就会出现类型转换异常:ClassCastException
- 拿一个子类的对象,当做父类的对象来用使用
- 向上造型是默认的,不需要运算符
- 向上造型总是安全的。也就是 父子
通过上面分析,Item分析有两个子类型,分别是:Course和Video。
当一个父类存在多个子类型的时候,item就是一种多态变量。
item而这种多态变量,会根据自身的数据类型,自动去匹配子类的方法 也就是说:
item 这个动作的时候,java会自动去匹配实际的类型。而这个事情就称之为多态。
而 item.方法 这个动态称之为:函数绑定
- 当通过对象变量调用函数的时候,调用哪个函数这个事情叫做绑定、
- 静态绑定:根据变量的声明类型来决定(也就是说你这个变量的申明类型,我就调用这个申明类型的函数。)
- 动态绑定:根据变量的动态类型来决定(也就是说:当实际管理的对象类型是什么,我就用那个类型的函数, 因为编译器在编译的时候,根本不知道你这个具体的类型是什么?在java中选择都是动态绑定来处理函数的绑定。)
- 在成员函数中调用其他成员函数也可以通过this这个对象变量来调用。
比如在item.print这行的时候,其实在编译的时候并不知道具体的类型是什么。所以只能在运行的时候才能确认具体的类型。
对于像java这样的程序语言来说,默认所有的绑定都是:动态绑定。
- 覆盖前提:继承关系
- 子类和父类中存在名字和参数表完全相同的函数,那么就存在覆盖关系
- 通过父类的变量调用存在覆盖关系的函数时,会调用变量当时所管理的对象所属的子类的函数。
- 类:它描述一类事物的的行为和状态(特征)的模板。
- 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
类模板的作用:就为了给的对象的创建提供了一模板
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。 ==局部变量的生命周期:跟随方法执行结束而死亡
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。==给对象创建提供了依据模板,成员变量存储在方法区的类信息中。它申请空间的时机,创建对象new User() , 对象死亡就消亡了==
- 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。它存储在方法区的静态区中,而且静态成员在编译的时候就存储进去了。
一个类可以拥有多个方法,在上面的例子中:eat()、run()、sleep() 和 name() 都是 Dog 类的方法。
1.1. 对象管辖的范围
- 成员变量
- 成员方法
1.2. 类管辖的范围
- 静态成员
比如:Item.java
证明观点:什么是类的模板,类的信息是如何在内存空间中进行存储的呢?
加载程序到JVM中的时机:
- 执行main函数
- 启动tomcat
1.3. 构造方法
每个类都有构造方法。
如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。
构造方法的名称必须与类同名,一个类可以有多个构造方法。
1.4. 创建对象
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。 (1:准备一个class)
- 实例化:使用关键字 new 来创建一个对象。(2:new 去标识出来创建对象)
- 初始化:使用 new 创建对象时,会调用构造方法初始化对象。(3:会调用构造函数去java堆中申请空间)
含有abstract修饰符的class即为抽象类,abstract 类不能创建实例对象。
含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。
abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。
如果子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
抽象类:其是比普通类多了一个抽象方法, 抽象方法它是子类的一种约束,告诉子类一定要覆盖和重写
的方法
2.1 为什么会存在抽象类呢?
原因是在实际的业务中,普通的父类很多时候无法起到约束子类的作用,比如:重写的方法。
- 因为能够让子类重写的方法,大部分情况父类是不需要去做事情,也就是必须让子类自身去实现。普通的父类是起不到约束的作用,也就是说,父类中需要覆盖的方法和普通方法这个时候就难以分辨和区分。所以就有了抽象方法abstract。==后续的接口更加能体现的淋漓尽致。==
- 我们知道抽象类。可以定义抽象方法和非抽象方法。==那么父类中的非抽象方法的意义是什么呢?其实还是回归到继承的概念:职责分担,大部分父类的非抽象方法就是去分担子类的业务,这样便于后续的维护和升级,这样就不需要去修改每个子类。只需要修改父类的方法,当然前提是方法的访问权限必须是:public或者protected的,如果是缺省的就必须在同包package中。
- 抽象类,在平时的业务中那些场景下可以用到抽象类呢?
-
- 比如springmvc路由的继承
- hibernate、jdbctempalte中的通用类的增删改查
- 还有就是spring框架中存在大量的抽象类,其意义就是:责任分担。
2.2 抽象类可以继承抽象类吗?
当然可以,毕竟其实抽象类就是多了一个关键词而已。
比如:spring框架源码中很多这样的存在。
2.3 疑虑,抽象类可以new吗?
抽象类,还是class。那么能实例化吗?它是一种多态机制的体现机制。
答案是:不可以的?
2.4 抽象类化有构造函数,抽象类存在的构造函数的意义是什么?
- 给子类的构造函数通过super()方法给抽象类的私有赋值使用
2.5 抽象类可以继承普通类吗?
可以,但是一般不会这样做,有点本末倒置的味道。
2.6 抽象类可以继承抽象类吗?
- 可以,存在于spring框架源码大量的存在。--- 职责分担
- java中继承原则:单一继承,多实现
2.7 抽象类A 继承 抽象类B B的抽象方法,A一定覆盖吗?
不用,比如
从上面可以得到一个结论,如果具体子类继承了抽象类,就必须把所以的抽象方法进行覆盖。
这个jdk规定事情、这也是java多年来的毛病和问题?
2.8 总结
- 抽象类:其实比普通多了关键词abstract,而这个关键字只类中的方法起到约束作用,同时代表这个类不能实例化
- 抽象类,可以继承普通类,也可以继承抽象类,也实现接口。
3.1 JDK类的继承存在的问题
- java单一继承,多实现
- 如果多个抽象类中存在多个抽象方法,其子类必须要重写所有抽象方法。
接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。
- 接口中的方法定义默认为public abstract类型。
- 接口中的成员变量类型默认为public static final。都是静态常量
- jdk1.8之后允许定义默认方法和静态方法
3.2 接口的定义
接口:
实现类:
3.3 默认方法
定义默认方法,就是告诉子类你可以不用强制去重写这些方法,可以选择性的覆盖。
3.4 静态方法
定义静态方法代表,这个方法可以通过接口类之间去调用,是公用的方法。
3.5 接口是可以多继承接口的
3.6 Java为什么要存在接口?
在开发中,我们很多时候在框架代码中经常看到一个接口一个实现类的定义方式
。比如:
由此可以看出,我们使用接口的目的
- 规范,约束 (一定是一个接口有多个子类的时候它价值就体现出来,也是多态的最佳体现)
- 方便后续的扩展
- Jdk动态代理,在框架大量的存在比如mybatis的mapper、Spring中的Aop
- 抽象类可以有构造方法,接口中不能有构造方法。
- 抽象类中可以有普通成员变量,接口中没有普通成员变量
- 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法
- 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
- 抽象类中可以包含静态方法,接口中不能包含静态方法,==JDK1.8以后允许==
- 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
- 一个类可以实现多个接口,但只能继承一个抽象类。 单一继承多实现
- Jdk1.8以后新增了默认方法default和static方法,慢慢替代抽象类的的含义,但是不能完全的消除抽象类。
JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。
用法一:常量
在JDK1.5 之前,我们定义常量都是: public static final.... 。
现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
Java代码
用法二:switch
JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。
Java代码
用法三:向枚举中添加新方法
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。
而且 Java 要求必须先定义 enum 实例。
用法四:覆盖枚举的方法
用法五:实现接口
所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
用法六:使用接口组织枚举
Java代码
用法七:关于枚举集合的使用
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的 key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。
总结
enum这个关键字,可以理解为跟class差不多,这也个单独的类。可以看到,上面的例子里面有属性,有构造方法,有getter,
也可以有setter,但是一般都是构造传参数。还有其他自定义方法。
那么在这些东西前面的,以逗号隔开的,最后以分号结尾的,这部分叫做,这个枚举的实例。
也可以理解为,class new 出来的实例对象。这下就好理解了。
只是,class,new对象,可以自己随便new,想几个就几个,
而这个enum关键字,他就不行,他的实例对象,只能在这个enum里面体现。
也就是说,他对应的实例是有限的。这也就是枚举的好处了,限制了某些东西的范围,
举个栗子:一年四季,只能有春夏秋冬,你要是字符串表示的话,那就海了去了,
但是,要用枚举类型的话,你在enum的大括号里面把所有的选项,全列出来,那么这个季节的属性,对应的值,只能在里面挑。
不能有其他的。