3000字帮你彻底搞懂Java抽象类与接口的区别(含JDK8接口新增三种方法与丰富案例)
Java-OOP
1-Final
1.1简介
final关键字是最终的意思,可以修饰:类、方法、变量。
- 修饰类:该类被成为最终类,特点是不能被继承了。
- 修饰方法:该方法被称为最终方法,特点是不能被重写了。
- 修饰变量:该变量有且仅能被赋值一次。
1.2注意
- final修饰基本类型的变量,变量存储的数据不能被改变。
- final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容可以被改变。
final修饰类,不可被继承。
工具类中的方法添加final,会显得你的程序更加优雅。
final可以用于保护成员变量。
1.3常量
- 使用了static final 修饰的成员变量就被称为常量。
- 作用:常用于记录系统的配置信息。
使用常量记录系统配置信息的优势、执行原理
-
代码可读性更好,可维护性也更好。
-
程序编译后,常量会被“宏替换”:出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。
2-单例类(设计模式)
- 一个问题通常有n种解法,其中有一个解法是最优解,这个最优解法被人总结出来,称之为设计模式。
- 设计模式有20多种,对应20多种软件开发中会遇到的问题。
关于设计模式,主要学什么?
- 解决什么问题?
- 怎么写?
2.1单例设计模式
- 作用:确保某个类只能创建一个对象。
- 经典例子:系统控制器
2.1.1饿汉式单例写法-实现步骤
把类的构造器私有。
定义一个类变量记住类的一个对象。
定义一个类方法,返回对象。
但是这种实现方法并不专业,因为如果我们如果执行如下操作
就会输出null,所以我们可以直接在定义A类时添加final
或者我们可以把public修改为private,但是我们需要再新写一个方法。
单例有很多形式,我们刚才举例的是饿汉式单例:拿对象时,对象早就创建好了,接下来我们讲一下懒汉式单例。
2.1.2懒汉式单例
简介:用对象时,才开始创建对象。
写法:
把类的构造器私有。
定义一个静态变量用于存储对象。
提供一个静态方法,保证返回的是同一个对象。
没有谁好谁坏,只是涉及到具体案例的选择不同,相对来说,第一次拿对象时,饿汉式是比懒汉式更快的,但是如果一个类始终不被使用,但是饿汉式已经创建了。
3-枚举类
- 枚举类是一种特殊类。
3.1枚举类的写法
特点:
- 枚举类中的第一行,只能写枚举类的对象名称,并且要用逗号隔开。
- 这些名称,本质是常量,每个常量都记住了枚举类的一个对象。
- 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象。
- 编译器为枚举类新增了几个方法。
3.2枚举类的常见应用场景
枚举类很适合做信息分类和标志。
比如我们现在要做一个用户输入上下左右移动的案例,我们有两种办法,第一种就是拿常量做,第二种就是拿枚举做。
如果使用枚举做
我们在使用程序的时候就只能按照枚举类中的四个值使用,我们的参数值会受到枚举类的约束。
4-抽象类
在java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法。
- abstract修饰类,这个类就是抽象类。
- abstract修饰方法,这个方法就是抽象方法。
4.1抽象类的注意事项、特点
- 抽象类不一定要有抽象方法,有抽象方法的类必须是抽象类。
- 类有的成员:成员变量、方法、构造器、抽象类都可以有。
- 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现。
- 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类。
4.2抽象类的好处
父类知道每个子类都要做某个行为,但每个子类要做的情况不一样,父类就定义成抽象方法,交给子类去重写实现,我们设计这样的抽象类,就是为了更好的支持多态。
4.3模版方法设计模式
- 提供一个方法作为完成某类功能的模版,模版方法封装了每个实现步骤,但允许子类提供特定步骤的实现。
- 模版方法设计模式可以:提高代码的复用、并且简化子类设计。
4.3.1写法
- 定义一个抽象类。
- 在里面定义两个方法
一个是模版方法:把共同的实现步骤放里面去。
一个是抽象方法:不确定的步骤实现,交给具体的子类来完成。
建议:用final修饰模版方法,因为可以确保模版方法不会被重写,我们的目的是模版方法是被子类直接使用,不能被子类重写,一旦子类重写模版方法,模版就失效了。
5-接口
5.1接口的概述
- Java提供了一个关键字interface定义成接口。
JDK8之前接口只能在内部写成员变量(常量)和成员方法(抽象方法)
-
注意:接口不能创建对象。
-
接口是用来被类实现(implements)的,实现接口的类称为实现类,一个类可以同时实现多个接口。(接口可以理解为干爹)
5.2接口的好处
弥补了类单继承的不足,一个类可以同时实现多个接口,使类的角色更多,功能更强大。
让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现(更利于程序的解耦合)
5.3接口综合小案例
请设计一个班级学生的信息管理模块:学生的数据有:姓名、性别、成绩
功能1:要求打印出全班学生的信息; 功能2:要求打印出全班学生的平均成绩。
------------------------------------------------------------------------------------------------------------------------
注意!以上功能的业务实现是有多套方案的,比如:
第1套方案:能打印出班级全部学生的信息;能打印班级全部学生的平均分。
第2套方案:能打印出班级全部学生的信息(包含男女人数);能打印班级全部学生的平均分(要求是去掉最高分、最低分)。
要求:系统可以支持灵活的切换这些实现方案。
5.4JDK8开始,接口新增的三种方法
-
1.默认方法(普通实例方法):必须加default修饰
默认使用public修饰
如何调用?使用接口的实现类的对象来调用。 -
2.私有方法(JDK9才开始支持的)
私有的实例方法(也就是对象方法,但是接口没有实例化对象)。
那如何调用接口的私有方法?只能使用接口内的实例化对象调。 -
3.静态方法
默认使用public修饰
如何调用?直接使用当前接口名来调用。
但是实际上,这个新特性在我们实际使用中几乎不会用到,如果硬要说优点。
- 增强了接口的能力,更便于项目的扩展和维护中。
5.5接口的注意事项
目标:
1、接口与接口可以多继承:一个接口可以同时继承多个接口[重点]。
- 类与类:单继承 一个类只能继承一个父类。
- 类与接口:多实现 一个类可以实现多个接口。
- 接口与接口:多继承 一个接口可以同时继承多个接口。
2、一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承,也不支持多实现。
- 并且如果方法签名冲突,类也是不可以支持多实现的。
3、一个类继承了父类,又同时实现了接口,如果父类中和接口中有同名的默认方法,实现类会优先用父类的。
4、一个类实现了多个接口,如果多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可。
但是那个抽象的调用,国内的开发人类基本不会使用,但是是可以行得通的。
5.6接口和抽象类的区别
这个需要有很强的语法功底才能理解明白,因为一千个人有一千个oop的理解。
相同点:
- 都是抽象形式,都可以有抽象方法,都不能创建对象。
- 都是派生子类形式:抽象类是被子类继承使用,接口是被实现类实现。
- 继承抽象类或者实现接口都必须重写所有的抽象方法,否则自己要成为抽象类或者报错。
- 都能支持多态,都能够实现解耦合。
不同点:
- 抽象类中可以定义类的全部不同成员,接口只能定义常量、抽象方法(JDK新增三种方式)
- 抽象类只能被单继承,接口可以被类多实现。
- 一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)
- 抽象类体现模版思想,更适合做父类实现代码的复用性。(最佳实践:IO流)
- 接口更适合做功能的解耦合,解藕合性更强更灵活。(最佳实践:集合)
使用,接口是被实现类实现。
3. 继承抽象类或者实现接口都必须重写所有的抽象方法,否则自己要成为抽象类或者报错。
4. 都能支持多态,都能够实现解耦合。
不同点:
- 抽象类中可以定义类的全部不同成员,接口只能定义常量、抽象方法(JDK新增三种方式)
- 抽象类只能被单继承,接口可以被类多实现。
- 一个类继承抽象类就不能再继承其他类,一个类实现了接口(还可以继承其他类或者实现其他接口)
- 抽象类体现模版思想,更适合做父类实现代码的复用性。(最佳实践:IO流)
- 接口更适合做功能的解耦合,解藕合性更强更灵活。(最佳实践:集合)