Comparable接口
当我们想要比较两个基本数据类型的大小时直接用 > , < , = 就可以了,那么如果是自定义的类要根据什么规则进行比较呢?这就用到了Comparable接口,接口中定义的就是一种规范,通过重写接口中的compareTo方法,定义比较规则,就实现了自定义类型的比较
//调用接口 class Man implements Comparable<Man>{ public String name; public int age; public Man(String name,int age){ this.name = name; this.age = age; } public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } //重写接口方法 public int compareTo(Man m) { return this.age - m.age; } } public class Text01 { public static void main(String[] args) { Man man1 = new Man("li",18); Man man2 = new Man("wang",20); System.out.println(man1.compareTo(man2));//输出-2 } }
谁调用compareTo方法,this就代表谁
String类型比较
上面比较的age是整型,可以相减,那如果是String 类型呢
可以看出,Java中的String类也实现了Comparable接口,同时也重写了compareTo方法
那么我们只需要调用就可以了
public int compareTo(Man m) { return this.name.compareTo(m.name); }
多个对象的比较
import java.util.Arrays; class Man implements Comparable<Man>{ public String name; public int age; public Man(String name,int age){ this.name = name; this.age = age; } public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } public int compareTo(Man m) { return this.name.compareTo(m.name); } } public class Text01 { public static void main(String[] args) { Man man1 = new Man("li",18); Man man2 = new Man("wang",20); Man man3 = new Man("zhang",22); Man[] men = {man1,man2,man3}; //使用Arrays类的sort方法对数组进行排序 Arrays.sort(men); System.out.println(Arrays.toString(men)); } }
运行结果:
可以看出,是按照重写后的compareTo方法进行排序的
这一次程序报错了,类型转换的错误
当点到出错的地方来看
当把之前的注释取消,源码底层就会把Man强转为Comparable,调用compareTo方法,而此时由于compareTo重写了,就会调用重写后的方法,排序也会根据重写之后的compareTo方法进行排序。
简单模拟一下Array.sort对自定义类型的排序
public static void main(String[] args) { Man man1 = new Man("li",18); Man man2 = new Man("wang",20); Man man3 = new Man("zhang",22); Man[] men = {man1,man2,man3}; //使用Mysort方法对数组进行排序 Mysort(men); System.out.println(Arrays.toString(men)); } public static void Mysort(Comparable[] comparables){ for(int i = 0;i < comparables.length - 1;i++){ for(int j = 0;j< comparables.length - 1 - i;j++){ //如果后面的元素比前面的元素小,则交换它们的位置 if(comparables[j].compareTo(comparables[j+1]) > 0){ Comparable temp = comparables[j]; comparables[j] = comparables[j+1]; comparables[j+1] = temp; } } } }
所以当调用Arrays.sort给自定义的类型进行排序的时候,也必须实现Comparable的接口
但是无论是比较age还是name,用以上方法都比较固定,不够灵活,为了解决这个问题,我们来介绍下一个接口
Comparator接口
public class BrandComparator implements Comparator<Car>{ public int compare(Car o1, Car o2) { return o1.getBrand().compareTo(o2.getBrand()); } }
调用接口之后重写compare方法
public static void main(String[] args){ Car car1 = new Car("benz","black",200); Car car2 = new Car("audi","white",250); Car[] cars = {car1,car2}; //使用Comparator接口的compare方法 BrandComparator brandComparator = new BrandComparator(); //传入比较器 Arrays.sort(cars,brandComparator); //toString方法 System.out.println(Arrays.toString(cars)); for(Car car:cars){ System.out.println("品牌:" + car.getBrand()); System.out.println("颜色:" + car.getColor()); System.out.println("速度:" + car.getSpeed()); } }
也可以直接调用方法,单独比较
BrandComparator brandComparator = new BrandComparator(); int res = brandComparator.compare(car1,car2); System.out.println(res);
这样就比较灵活,想要根据哪个属性比较,就定义一个类去实现Comparator接口,再定义比较的规则
Cloneable接口
public class Person { public String name; public int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
创建一个Person类之后,实现对象的克隆
虽然Person类里面没有clone方法,但是Object类里面有,每一个类都默认继承与Object类,但此时还是报错了,这就需要在Person类中重写clone方法
protected Object clone() throws CloneNotSupportedException { return super.clone(); }
加上之后还是错的,原因是,自定义类型想要进行克隆还要实现Cloneable接口
点进源码发现Cloneable接口没有写任何方法,是一个空接口,空接口也叫做标记接口,表示当前类是可以被克隆的
之后还要处理一下异常,再对返回值类型进行强转,因为此时返回的是Object类型的,这样就可以正常执行了
public static void main(String[] args) throws CloneNotSupportedException{ Person person1 = new Person("张三", 20); Person person2 = (Person) person1.clone(); }
具体过程就是创建person1对象之后,再克隆一份数据,创建person2,把克隆出的数据赋值给person2
浅拷贝
在原来的基础上再加上一个Money类,此时再对克隆后的值进行修改
可以看出,当把person1的money修改之后,两个是都会发生改变的,这种就叫做浅拷贝
此时就是只克隆了Person的对象,没有克隆Money的对象
深拷贝
如果想要Money也进行克隆,就需要实现Cloneable接口,同时重写clone方法
class Money implements Cloneable{ public double money = 9.9; protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
Person类的clone也要重写
Person克隆之后,Money也进行克隆,就是深拷贝