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就像是老师
此时再观察内存布局:
此时这种拷贝方式就称为"深拷贝".