Comparable+Comparator+Cloneable接口
Posted 爱敲代码的三毛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Comparable+Comparator+Cloneable接口相关的知识,希望对你有一定的参考价值。
文章目录
Comparable
当我们需要对一个自己写的类进行排序(Collections.sort
和Arrays.sort
)的时候,,就要使用到Comparable
接口。
该接口中有一个compareTo
方法,该方法其实就是一比较规则。
public interface Comparable<T>
public int compareTo(T o);
然后比较当前对象和参数对象的大小关系(按分数来算).
- 如果当前对象应排在参数对象之前, 返回小于 0 的数字;
- 如果当前对象应排在参数对象之后, 返回大于 0 的数字;
- 如果当前对象和参数对象不分先后, 返回 0
所以如果自己的类需要进行排序的时候,就需要实现Comparable
该接口,并重写compareTo
方法,该法就可以通过指定字段进行排序,比如年龄。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class Student implements Comparable<Student>
int id;
String name;
int age;
public Student(int id, String name, int age)
this.id = id;
this.name = name;
this.age = age;
@Override
public String toString()
return "Student" +
"id=" + id +
", name='" + name + '\\'' +
", age=" + age +
'';
// 谁调用的compareTo,谁就是this
@Override
public int compareTo(Student o)
return this.age -o.age;
public class TestDemo
public static void main(String[] args)
List<Student> students = new ArrayList<>();
students.add(new Student(2,"张三",20));
students.add(new Student(3,"李四",18));
students.add(new Student(1,"王五",15));
System.out.println(students);
Collections.sort(students);
System.out.println(students);
运行结果
[Studentid=2, name='张三', age=20, Studentid=3, name='李四', age=18, Studentid=1, name='王五', age=15]
[Studentid=1, name='王五', age=15, Studentid=3, name='李四', age=18, Studentid=2, name='张三', age=20]
该接口对类的侵入性比较强,但是如果这个比较规则已经被很多人使用,你突然想换个比较规则,如果修改比较规则必然会造成损失,所以这个方方法对类的侵入性太强了,并不是特别好。
Comparator
刚刚我们说 Comparable 对类的侵入性太强了,但有另外一个接口它十分灵活。就是Comparator 。
代码示例:
我们写了两个类,分别实现了 Comparator 这个接口,一个是用年龄比较,一个是用姓名比较。我们叫做比较器.
import java.util.Comparator;
public class AgeComparator implements Comparator<Student>
@Override
public int compare(Student o1, Student o2)
return o1.age-o2.age;
import java.util.Comparator;
public class NameComparator implements Comparator<Student>
@Override
public int compare(Student o1, Student o2)
return o1.name.compareTo(o2.name);
再来看原来的代码,我们的Student并没有实现任何接口,也没有重写compareTo 方法。
只是实例化了刚刚上面两个比较器,在用sort排序时,传过去了两个参数,一个是要排序的集合,一个是我们写的比较器对象。
class Student
int id;
String name;
int age;
public Student(int id, String name, int age)
this.id = id;
this.name = name;
this.age = age;
@Override
public String toString()
return "Student" +
"id=" + id +
", name='" + name + '\\'' +
", age=" + age +
'';
public class TestDemo
public static void main(String[] args)
List<Student> students = new ArrayList<>();
students.add(new Student(3,"李四",18));
students.add(new Student(1,"王五",15));
students.add(new Student(2,"张三",20));
System.out.println(students);
//按姓名排序
NameComparator nameComparator = new NameComparator();
Collections.sort(students,nameComparator);
System.out.println(students);
// 按年龄排序
AgeComparator ageComparator = new AgeComparator();
Collections.sort(students,ageComparator);
System.out.println(students);
运行结果
[Studentid=3, name='李四', age=18, Studentid=1, name='王五', age=15, Studentid=2, name='张三', age=20]
[Studentid=2, name='张三', age=20, Studentid=3, name='李四', age=18, Studentid=1, name='王五', age=15]
[Studentid=1, name='王五', age=15, Studentid=3, name='李四', age=18, Studentid=2, name='张三', age=20]
Comparator
接口,如果要进行比较只需要根据自己的需要写一个比较器就好了,并不像第一个接口那样直接写死了。
Cloneable
Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现Clonable接口
- 实现Clonable接口
- 记住要处理异常
- 重写 Object 的 clone 方法
class Person implements Cloneable
String name;
int age;
public Person(String name, int age)
this.name = name;
this.age = age;
@Override
public String toString()
return "Person" +
"name='" + name + '\\'' +
", age=" + age +
'';
@Override
protected Object clone() throws CloneNotSupportedException
return super.clone();
public class CloneableDemo
public static void main(String[] args) throws CloneNotSupportedException
Person std1 = new Person("张三",18);
Person std2 = (Person) p1.clone();
System.out.println(std1);
System.out.println(std2);
运行结果
Personname='张三', age=18
Personname='张三', age=18
此时的内存布局
如果一个类里的成员变量是另外一个类,使用clone
对其进行拷贝
浅拷贝
class Test
int val;
public Test(int val)
this.val = val;
@Override
public String toString()
return "Test" +
"val=" + val +
'';
class Person implements Cloneable
String name;
int age;
Test t;
public Person(String name, int age)
this.name = name;
this.age = age;
@Override
public String toString()
return "Person" +
"name='" + name + '\\'' +
", age=" + age +
", t=" + t +
'';
@Override
protected Object clone() throws CloneNotSupportedException
return super.clone();
public class CloneableDemo
public static void main(String[] args) throws CloneNotSupportedException
Person std1 = new Person("张三",18);
std1.t = new Test(100);
Person std2 = (Person) p1.clone();
std2.t.val = 200;
System.out.println(std1);
System.out.println(std2);
运行结果
Personname='张三', age=18, t=Testval=200
Personname='张三', age=18, t=Testval=200
当我们对拷贝后的对象也就是p2里的Test示例进行修改时,p1也发生了改变。此时就是一个典型的浅拷贝
此时的内存布局,这个拷贝就是将一个对象原样克隆了一份,它其时两个对象里的Test示例对象还是指向的同一个 对象
深拷贝
要想实现深拷贝,就得修改clone
方法,再让其包含的Test类也要实现Cloneable
接口重写clone接口,让Person对象在拷贝的同时把Test示例也给拷贝,这样就实现深拷贝。
class Test implements Cloneable
int val;
public Test(int val)
this.val = val;
@Override
public String toString()
return "Test" +
"val=" + val +
'';
@Override
protected Object clone() throws CloneNotSupportedException
return super.clone();
class Person implements Cloneable
String name;
int age;
Test t;
public Person(String name, int age)
this.name = name;
this.age = age;
@Override
public String toString()
return "Person" +
"name='" + name + '\\'' +
", age=" + age +
", t=" + t +
'';
@Override
protected Object clone() throws CloneNotSupportedException
Person person = (Person) super.clone();
person.t = (Test) this.t.clone();
return person;
public class CloneableDemo
public static void main(String[] args) throws CloneNotSupportedException
Person p1 = new Person("张三",18);
p1.t = new Test(100);
Person p2 = (Person) p1.clone();
p2.t.val = 200;
System.out.println(p1);
System.out.println(p2);
运行结果
Personname='张三', age=18, t=Testval=100
Personname='张三', age=18, t=Testval=200
此时的内存布局
以上是关于Comparable+Comparator+Cloneable接口的主要内容,如果未能解决你的问题,请参考以下文章