初见乍惊欢,久处亦怦然
大家好,这里是新一,请多关照。首先祝大家中秋团圆,在这中秋佳节,怎么不来一篇博客呢,接下来让我们了解一下JAVA三大常用接口和深拷贝吧。(以下结果均在IDEA中编译)希望在方便自己复习的同时也能帮助到大家。
废话不多说,直接进入我们的文章。
一. 三大接口
此处我们以学生信息排序为例,给大家讲解一下这三大接口(Comparable
Comparator,Clonable)
我们知道JAVA中可以用Arrays.sort对数组进行排序,例如我们对下列数组进行排序
public static void main1(String[] args) {
int[] array = {1,21,3,14,5,16};
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
其中的sort是根据数组元素的大小进行排序的,那么如果我们用Arrays.sort来排序复杂对象呢?如下
class Student implements Comparable<Student>{
public int age;
public String name;
public double score;
public Student(int age, String name, double score){
this.age = age;
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", score=" + score +
'}';
}
}
public class Test {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(14,"张三",78.9);
students[1] = new Student(13,"李四",86.9);
students[2] = new Student(12,"王麻子",99.5);
System.out.println(Arrays.toString(students));
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}
那么现在可以排序吗,那是肯定不行的,因为sort并不知道你要根据什么特性来排序,我们先来查看一下sort的底层代码
2. 按住Ctrl点击legacyMerfeSort
3.按住Ctrl点击mergeSort
4. 此处我们发现这里有个compareTo函数,按住Ctrl并点击
我们发现这个函数是没有实现的,难道是意外吗?当然不是,我们再看看这个类
它是个Comparable接口,这个比较的函数CompareTo就需要我们自己来实现,如下:
//谁调用这个方法谁就是this
@Override
public int compareTo(Student o) {
return this.age - o.age;//根据年龄排序
}
class Student implements Comparable<Student>{
public int age;
public String name;
public double score;
public Student(int age, String name, double score){
this.age = age;
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", score=" + score +
'}';
}
//谁调用这个方法谁就是this
@Override
public int compareTo(Student o) {
//return this.age - o.age;
return this.name.compareTo(o.name);
}
}
public class Test {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(14,"张三",78.9);
students[1] = new Student(13,"李四",86.9);
students[2] = new Student(12,"王麻子",99.5);
System.out.println(Arrays.toString(students));
Arrays.sort(students);
System.out.println(Arrays.toString(students));
}
}
没错,我们需要修改类里边的源码才能对排序特性进行修改,那么这样必然会存在一下问题,要知道,公司里边的源码是不能随便动的,因此,Comparable实现的接口有很大的缺陷 - 太嵌入
那么有没有更好的方法来实现我们的sort结构体排序呢?当然有,那就是我们的Comparator接口
我们同样按住Ctrl再点击Comparator
既然这个是个接口,我们就需要重写其中的方法compare,调用这个接口并重写这个方法的类我们就称为比较器
class AgeComparstor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
class ScoreComparstor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return (int)(o2.score - o1.score);
}
}
class NameComparstor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
此即为学生这个对象排序的三个比较器,那么怎么调用呢?
class Student {
public int age;
public String name;
public double score;
public Student(int age, String name, double score){
this.age = age;
this.name = name;
this.score = score;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
", name='" + name + '\'' +
", score=" + score +
'}';
}
}
class AgeComparstor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.age - o2.age;
}
}
class ScoreComparstor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return (int)(o2.score - o1.score);
}
}
class NameComparstor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public class Test {
public static void main(String[] args) {
Student[] students = new Student[3];
students[0] = new Student(14,"张三",78.9);
students[1] = new Student(13,"李四",86.9);
students[2] = new Student(12,"王五",99.5);
System.out.println(Arrays.toString(students));
AgeComparstor ageComparstor = new AgeComparstor();
ScoreComparstor scoreComparstor = new ScoreComparstor();
NameComparstor nameComparstor = new NameComparstor();
Arrays.sort(students,nameComparstor);
System.out.println(Arrays.toString(students));
}
}
我们只需要在main函数中new一个比较器对象,再将其加入到Arrays.sort方法中即可排序, Comparator对类的侵入性非常弱 ,故在一般情况下推荐这个接口
Clonable 接口顾名思义它可以克隆我们的一个对象,在Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.
class Person implements Cloneable{
public int age;
public void eat() {
System.out.println("吃!");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = super.clone();
return tmp;
}
}
public class Clonable {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
person.age = 99;
Person person2 = (Person) person.clone();
System.out.println(person2);
System.out.println("===============");
person2.age = 199;
System.out.println(person);
System.out.println(person2);
}
}
此时我们会发现person2就是我们克隆的对象了,那么我们改变person2的值会影响person1吗,答案是否定的的,因为我们所实现的这个方法是所谓的深拷贝,它克隆了我们的这个对象,同样在堆区也就对了一份找个对象,两个对象互不影响
二. 深拷贝
在上述用例中我们实现的方法即为深拷贝,但并不是Clonable这个接口是深拷贝,是我们实现的这个方法是深拷贝,取决于我们如何实现的方法,那么为什么呢?我们再给个用例
class Money implements Cloneable{
public double m = 12.5;
}
class Person implements Cloneable{
public int age;
public Money money = new Money();
public void eat() {
System.out.println("吃!");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = super.clone();
return tmp;
}
}
public class Clonable {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
Person person2 = (Person) person.clone();
System.out.println(person.money.m);
System.out.println(person2.money.m);
System.out.println("===================");
person2.money.m = 99.99;
System.out.println(person.money.m);
System.out.println(person2.money.m);
}
}
此时会发现当我们改变拷贝对象时,原对象也发生变化,这就说明对象并未被拷贝,而只是引用被拷贝了一份,因此这就叫浅拷贝
我们也可以把它变成深拷贝。
class Money implements Cloneable{
public double m = 12.5;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();//拷贝引用对象
}
}
class Person implements Cloneable{
public int age;
public Money money = new Money();//引用类型
public void eat() {
System.out.println("吃!");
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
Person tmp = (Person)super.clone();
tmp.money = (Money) this.money.clone();//调用方法拷贝对象
return tmp;
}
}
public class Clonable {
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person();
Person person2 = (Person) person.clone();
System.out.println(person.money.m);
System.out.println(person2.money.m);
System.out.println("===================");
person2.money.m = 99.99;
System.out.println(person.money.m);
System.out.println(person2.money.m);
}
}
此时我们发现,实现了深拷贝。
家人们,学到这里我们已经学习完了三大接口与深拷贝了,也在这里祝大家节日快乐,后续新一会持续更JAVA的有关内容,学习永无止境,技术宅,拯救世界!