抽象类与接口
- 1 抽象类
- 1.1 定义与使用
- 1.2 抽象类和抽象方法使用原则
- 2 接口
- 2.1 定义
- 2.2 使用规则
- 3. JDK中内置接口
- 3.1 Comparable接口
- 3.2 Cloneable接口
- 抽象类与接口的对比
前言:如果强制要求子类必须覆写一些方法,则就会用到抽象类和抽象方法
1 抽象类
1.1 定义与使用
- 在面向对象的世界中,一切皆对象,但是某些类是比较抽象的概念,无法对应具体的实体,则这些类就可以作为抽象类。
即:若某些类的信息无法具体描述一个对象,只是作为具体对象的父类,这种类就能定义为抽象类。
eg:比如sharp、animal、person - 使用关键字
abstract
定义抽象类。抽象类是普通类的超集,只是比普通类多了一些抽象方法([0…N])而已。普通类有的,抽象类都有。 - 使用关键字
abstract
定义抽象方法。抽象方法没有方法体{}
,只有方法声明。
eg:
在 Java中,没有方法体的方法一定是抽象方法 (X)
还需要看关键字abstract,在Java中,native方法
也没有方法体,该方法不是抽象方法。本地方法是由C++实现的方法,Java只负责调用,方法体实现是C++代码。
1.2 抽象类和抽象方法使用原则
- 抽象类不能直接实例化对象,即便抽象类中没有任何抽象方法,也无法直接实例化对象。只能通过向上转型进行引用赋值。
Sharp sharp=new sharp();//错误
Sharp sharp=new Cycle();//正确,可以直接new一个子类对象
- 抽象类的子类若是普通类,则必须覆写抽象类中的所有抽象方法。若子类是抽象类,则一个抽象方法都可以不写。
- 强制要求子类必须进行方法覆写,保证多态的正常运行
- 抽象方法在没有加访问限定符时,为默认的
default
权限。
- abstract和其他关键字的使用
- private 和 abstract 能否同时修饰一个方法?
不能。private 修饰的方法却无法进行方法覆写;abstract 修饰的方法必须进行方法覆写。冲突! - final 和abstract 能否同时出现?
不能。final 修饰的类没有子类,不能覆写方法。 - static 和abstract 能否同时出现?
不能。static 修饰的方法不能被重写。
-
抽象类是普通类的超集
抽象类中仍然能够定义构造方法和普通方法,且仍然能够满足对象的实例化流程,先调用抽象类的构造方法而后调用子类的构造方法。 -
抽象类存在意义
抽象类就是在普通类的基础上进一步提取,只是比普通类多了一些抽象方法而已,抽象方法的存在要求子类必须进行方法重写,从而保证多态的正确执行!
2 接口
2.1 定义
- Java中可以看做是多个类的共同规范,接口也是引用数据类型
- 语法:
- 使用关键字
interface
定义接口。接口中99%都是抽象方法。
一般使用I
开头表示接口的命名。 - 子类使用
implement
实现接口,子类若是普通类,则必须覆写接口中所有的抽象方法。
一般来说,子类使用Impl
结尾,表示是接口的实现子类。
- 接口子类和抽象类子类的区别
- 接口的子类之间没有太多的联系,接口只是多个不同类之间相同的规范,表示一种水平方向上的混合规范。
- 抽象类属于继承体系结构之中,抽象类的子类之间具有许多的共性,抽取出子类的共有特征。
- 接口典型应用场景
- 表示一种规范/标准:USB接口、5G标准…都是一种规范
- 表示一种能力/行为:飞翔、游泳、跑…不同动物具备的能力不同,因此通过接口来描述
2.2 使用规则
-
接口是更加纯粹的抽象类,只有全局常量和抽象方法,没有构造方法,没有普通方法,因此,接口无法实例化对象,只能通过子类向上转型被接口引用接收。
-
接口的子类允许多实现,一个类可以使用
implement
实现多个父接口!(避免了抽象类的单继承局限性)
接口的子类不是is a
关系,一个子类可以同时满足多个标准或具备多种能力。
eg:手机类既满足5G标准,又满足USB标准,因此,手机这个类既实现5G接口,又要实现USB接口,可以实现多个接口。 -
因为接口中只有全局变量和抽象方法,因此在接口中,以下关键字全部可以省略不写。阿里编码规约明确表示,接口中只保留核心关键字,可以省略的坚决不写!只有接口有此规则!!!
public abstract
修饰常量:static final
-
子类若同时继承一个抽象类,实现多个接口。请先使用
extends
继承一个类,而后使用implements
实现多个接口。
- eg:接口表示能力示例
IRun
、ISwim
、IFly
接口
测试:
- 应用场景二:统一规范USB接口
使用鼠标、键盘来实现USB接口。
电脑类和USB接口的关系是啥?电脑是否需要实现USB标准
电脑是USB的使用者不是实现者。使用者表示需要自己插入到别的设备上,使用者自身具备USB连接口,只需要别的设备连接即可!
(鼠标实现了USB接口,只要某个设备含有USB接口,鼠标进行插入)
- 接口的多继承。接口和接口之间可以使用
extends
继承多个父接口,但是接口不能使用extends
继承类!接口存在多继承
- JDK8之后,接口中也允许存在普通方法,接口中的普通方法使用
default
定义。
3. JDK中内置接口
3.1 Comparable接口
JDK内置的对象比较接口 java.lang.Comparable
接口,自定义的类型要想让其具备可比较的能力,(1)实现java.lang.Comparable接口,(2)覆写compareTo方法。
public int compareTo(Object o)
{
return 0;
}
返回值类型int表示,当前对象和传入对象o作比较,根据返回值判断当前对象和传入对象o之间的大小关系。
(1) >0 的数,当前对象 > 传入对象
(2) <0 的数,当前对象 < 传入对象
(3) =0 的数,当前对象==传入对象
- 为什么传入参数是object类型?
因为不清楚传入的参数具体是什么类型的对象,不知道需要进行比较的是什么类型的子类,因此使用参数的最高统一化类型,只要是类进行比较,都可以使用Object进行接收。 - 对一个学生数组进行排序
public class Student implements Comparable{
private String name;
private int score;
//覆写Object类的compareTo方法
public int compareTo(Object o)
{
//1.先判断边界条件:传入的o是否为空;传入的o是否为Student类型对象
if(o==NULL||o instanceof Student)
{
//2.此时没有可比性,抛出异常
throw new IllegalArgumentException("参数非法!");
}
//3. 说明o合法且为Student类型的引用,向下转型将其还原为Student类型
Student stu=(Student)o;
return this.score-stu.score;
}
}
测试
public static void main(String[] args)
{
Student stu1=new Student("张三",95);
Student stu1=new Student("张三",95);
//此时的this指针指向stu1去和stu2比较
System.out.println(stu1.compareTo(stu2));
}
当Student类实现了Comparable接口,JDK的Array.sort就是按照compareTo方法的返回值进行大小排序。
- 使用冒泡排序对其进行排序
//参数对象是Comparable接口数组,只要传入的对象实现了Comparable接口,自然就是Comparable子类
public static void sort(Comparable[] array)
{
//外层循环表示所走趟数
for(int i=0;i<array.length-1;i++)
{
boolean isSwaped=false;
//内层循环进行一次,有序数组元素+1,将当前无序数组的最大值放在了数组末尾
for(int j=0;j<array.length-1-i;j++)
{
if(array[j].compareTo(array[j+1])>0)
{
Comparable temp=array[j];
array[j]=array[j+1];
array[j+1]=temp;
isSwaped=true;
}
}
//发现任意一次内层循环中,没有任何与元素交换,则整个数组已经有序
if(!isSwaped)
{
break;
}
}
}
- 总结
基本数据类型可以根据具体数值进行大小比较;
对于对象而言,内部所包含的属性不止一个,因此通过实现Comparable接口的compareTo方法的返回值进行比较。将复杂问题转化为int的大小关系比较。
3.2 Cloneable接口
- 1. 概念
要想让一个类具有可复制的能力(1)实现Cloneable接口(2)然后覆写Object类中的clone方法
在克隆的过程中是有新对象的产生,新对象的属性值和被克隆的对象完全一致。 - 2. 标记接口
Cloneable接口属于JDK的标记接口,类似的还有序列化接口Serializable,没有具体的方法。标记接口只要实现其子类,JVM运行起来就会识别这种标记,赋予其相应的能力;JVM识别所有实现了Cloneable的类,赋予其可复制的能力,打上可克隆的标记。
- 只有实现了Cloneable接口(打上标记)的类才能覆写clone方法,否则就会被JVM抛出异常
3. 深浅拷贝
(1)浅拷贝
被克隆的对象内部若包含其他类型的引用,则克隆后的对象,仍然保留原引用,不会产生新的对象。
浅拷贝只会将原对象内部的所有属性值复制一份,引用则只会复制引用的值,即地址,仍旧指向的是同一个对象。
(2)深拷贝 - (a)递归进行clone的调用
克隆对象内部包含其他类型的引用,其他类型的引用在克隆时也会调用克隆方法产生新对象。
- (b)进行序列化操作
广义上的序列化就是将任意的对象转为字节流
序列化:将任意对象转为字符串,json字符串,json的序列化
反序列化:将特定的字符串转为某个具体类的对象,json的反序列化
经过序列化得到的新对象一定是深拷贝对象。