Comparable与Comparator接口 -- Clonable接口与深浅拷贝

文章详细讲解了Java中Comparable接口用于自定义类型排序的原理和实现,以及Comparator接口如何提供更灵活的比较规则。同时,还介绍了浅拷贝和深拷贝的概念,通过示例代码展示了两者的区别和实现方法。
摘要由CSDN通过智能技术生成

1.Comparable接口

要对一个整形数组排序,可以使用Arrays.sort这个方法
在这里插入图片描述
但是对于自定义的类型,这样排序可能就无效了
在这里插入图片描述
查看报错信息:它说,Student类不可以转成Comparable

那如何要对一个自定义类型用Array.sort进行比较呢?
查看Array.sort源码可以看到,它把数组的每个元素都强转换成了Comparable类型,然后调用compareTo方法
在这里插入图片描述
通过查看源码发现Comparable是一个接口,里面有一个compareTo方法
在这里插入图片描述
在这里插入图片描述
既然底层代码逻辑是把数组中的每个元素转换成Comparable类型,那么我们为什么不可以让自定义类型实现这个接口呢
所以我们可以使自定义类型实现这个接口,并重写CompareTo这个方法,以此来按照自己所需要的比较规则进行比较

1.1代码实现

在这里插入图片描述

1.2代码片段解释

使用关键字 implements 让 Student 类实现Comparable接口;
在这里插入图片描述
重写 Comparable 接口的 ComparaTo 方法: 这个方法主要写比较规则(此处使用姓名比较),返回值是一个数字:大于0
, 小于0 或 等于0
在这里插入图片描述

也可以这样写:
在这里插入图片描述

注意:name后面的comparaTo方法是String的方法,因为name是String类型,打开String源码也能看见String也实现了Comparable接口

. main方法
在这里插入图片描述

运行结果:
在这里插入图片描述

上述Student类实现Comparable接口并重写comparaTo方法是为了能够执行我们自己的比较规则.

缺点:不够灵活,一旦在代码中写死了比较规则,以后就只能使用这个比较规则进行比较了

2.Comparator接口

为了解决上述接口不灵活的问题,使用Comparator接口就很有效的解决了

2.1代码实现

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.2代码片段解释

这里新建了两个类 AgeComparator 和 NameComparator 这两个类共同特点是 都实现了Comparator接口重写compare方法
在这里插入图片描述

然后再compare方法里写自己的比较规则,返回值也是一个 int 类型的,这两个类的作用是将来我要对自定义类型进行比较的时候,直接把引用传过去就行了
这种比较的优点是:当我传入的比较规则(比较器)不同,结果对自定义类型的排序也会不同

此时用来比较的这种类我们称作做"比较器"

那如何使用比较器呢?
实例化这个比较器,并把引用传给Arrays.sort的第二个参数:
在这里插入图片描述

可以看到结果是按照我们的需求进行比较的;
在这里插入图片描述

3.浅拷贝与深拷贝

在java中又两种数据类型,:
1,基本数据类型(内置类型):它存放的是值的本身
2.引用数据类型:它存放的是指向对象的地址

首先我们先看下面这段代码:
在这里插入图片描述

在这里插入图片描述
可以看出,打印的地址时相同的,也就是说,这两个引用指向了 Person(“zhansan”,10) 这个对象 ,此时这种现象可以理解为"复制",上面代码执行完,它们在内存中的布局是:
在这里插入图片描述
如何完整的克隆出一个相同的对象呢?

而下面代码则是真真正正的克隆了一个对象:
在这里插入图片描述
在这里插入图片描述

此时注意Person这个类实现了Cloneable接口并重写了clone方法,目的就是能够让这个类支持被克隆.
main方法中person1引用调用了clone方法,目的是把person1的对象克隆一份给person2,
因为这个clone方法是Object类的方法,而Object是所有类的父类,当一个父类引用给子类时,则需强转成子类类型(向下转型)
当代码执行完,它们在内存中的布局为:
在这里插入图片描述

当代码发生以下变化
在这里插入图片描述
在这里插入图片描述
查看运行结果看到,我只是把person1的money对象m改成了99,为什么person2也变了呢?
当代码走到第38行的时候,它做了什么呢?
它把person1指向 的对象克隆了一份给person2,接着改变了person1中的money对象所指向的对象m,并把它改成了99

此时它们在内存中的布局是这样的:
在这里插入图片描述
就是说,克隆了person1所指向的对象,并没有克隆person1所指向的money对象,当运行代码后,发现改变person1中的money对象的值,person2中也会随之而改变,因为这俩的money所指的是同一个对象.

此时我们可以称作这种拷贝方式为"浅拷贝"


那如何把person1中的所有对象,完整的拷贝到person2中呢?
要使money对象也可拷贝,需让Money类实现Cloneable接口,并重写clone方法:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
当代码走到第47行时,就会跑到第34行执行clone方法,我在这个方法里做了个啥?
首先,我定义了一个Person类型的引用person用来接收super.clone,那super.clone做了啥,它会把我的person1对象克隆一份,此时我的person对象就有了person1克隆的对象了,(super.clone会调用父类的clone方法,这里的父类指的是Object类,它的clone方法native修饰的,底层是用C或C++代码实现的)

接着把当前person对象money对象克隆一份,用person.money接收 最后return这个person对象,在外面用person2接收这个对象,此时再改变person1.money.m = 99 也就不会影响person2了.
这种方式就像,有一个临时的小组长,他把自己的作业和组员的作业收齐之后,交给老师,person就像这个小组长,super.clone 和 this.money.clone 就像是作业,person2就像是老师

此时再观察内存布局:
在这里插入图片描述

此时这种拷贝方式就称为"深拷贝".

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值