目录
一、通过接口对引用类型进行排序
1.为什么不直接使用Arrays.sort
class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "[" + this.name + ":" + this.age + "]";
}
}
public class Test {
public static void main(String[] args) {
Student[] students = new Student[3];
student[0] = new Student("zhansgan", 4);
student[1] = new Student("lisi", 8);
student[2] = new Student("abbc", 2);
Arrays.sort(students);
System.out.println(Arrays.toString(students));
// 运行出错, 抛出异常.
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable
}
}
因为students是引用数据,相当于c语言中的指针。虽说数组也是引用数据,但是数组里面存的都是相同的类型,而students不仅有String还有int类型。系统无法判断你要比较年龄还是名字。
2.怎么用接口怎么实现
这时候就可以用到我们的接口了,让我们的 Student 类实现 Comparable 接口, 并重写其中的 compareTo方法(年龄):
public class Student implements Comparable<Student> {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
return this.age-o.age;
}
}
public class Test {
public static void main2(String[] args) {
Student[] student = new Student[3];
student[0] = new Student("zhansgan", 4);
student[1] = new Student("lisi", 8);
student[2] = new Student("abbc", 2);
Arrays.sort(student);
System.out.println(Arrays.toString(student));
}
}
3.Comparable优点与缺点
Comparable的优点就是:能够实现引用类型的比较
Comparable的缺点就是:一旦写死,就只能用某一种方法(年龄或者名字等等)比较
二、Comparator选择器
那有没有比较灵活一点的比较呢?有那就是Comparator接口!
import java.util.Comparator;
import java.util.Arrays;
public class Student {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class AgeComparetor implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
return o1.age- o2.age;
}
}
public class NameComparetor implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o1.name.compareTo(o2.name);
}
}
public class Test {
public static void main1(String[] args) {
Student student1 = new Student("zhansgan", 4);
Student student2 = new Student("lisi", 8);
//年龄比较选择器
AgeComparetor ageComparetor=new AgeComparetor();
int ret1=ageComparetor.compare(student1,student2);
System.out.println(ret1);
//姓名比较选择器
NameComparetor nameComparetor=new NameComparetor();
int ret2=nameComparetor.compare(student1,student2);
System.out.println(ret2);
}
}
Comparable接口的出现使得比较可以更加灵活,并且不需要在原来的Student类进行修改,而是直接创造一个AgeComparable或NameComparable的类,需要的时候直接new对象就行了!
三、Cloneable接口
Object 类中存在一个 clone 方法,调用这个方法可以创建一个对象的 "拷贝"。但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常。
怎么克隆一个引用类型对象?
//类接入Cloneable接口,实现clone功能
class Student implements Cloneable {
public Money m = new Money();
public int age;
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"money=" + m +
", age=" + age +
'}';
}
//重写clone方法,右键generate->重写方法->clone()
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
//这里牵扯到异常,我后续的博客会讲解
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student(10);
Student student2 = (Student) student1.clone();
System.out.println(student2.m.money);
}
}
小提示:下列代码这个只有一份,跟拷贝不一样,student2没有生成空间放值,是直接指向student1
Student student2=student1;
四、浅拷贝与深拷贝
1.浅拷贝
什么是浅拷贝?先让我们看一段代码:
class Money {
public double money = 12.5;
}
class Student implements Cloneable {
public Money m = new Money();
public int age;
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"money=" + m +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1 = new Student(10);
Student student2 = (Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
student1.m.money = 100;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
}
//执行结果
12.5
12.5
100.0
100.0
如上代码,我们可以看到,通过clone,我们只是拷贝了Student对象。
但是Student对象中的Money对象,并没有拷贝。
通过studen2这个引用修改了m的值后,studen1这个引用访问m的时候,值也发生了改变。这里就是发生了浅拷贝。
2.深拷贝
假设我想修改student1中m,不想修改student2中m,这种就是深拷贝,代码实现:
class Money implements Cloneable{
public double money=12.5;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Student implements Cloneable{
public Money m=new Money();
public int age;
public Student(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"money=" + m +
", age=" + age +
'}';
}
@Override
protected Object clone() throws CloneNotSupportedException {
//return super.clone();
Student tmp=(Student) super.clone();
tmp.m=(Money) this.m.clone();
return tmp;
}
}
public class FurTest {
public static void main(String[] args) throws CloneNotSupportedException {
Student student1=new Student(10);
Student student2=(Student) student1.clone();
System.out.println(student1.m.money);
System.out.println(student2.m.money);
student2.m.money=100;
System.out.println(student1.m.money);
System.out.println(student2.m.money);
}
//执行结果
12.5
12.5
12.5
100.0
注意的是:
1.深拷贝需要两种重写clone。一种是studen自己的,一种是money的。
2.cloneable接口里面什么都没有,它是一个空接口,那为什么还要接入它呢?
答:一个类具备这个特性,才接入的接口。重要的是具不具备。