Java学习【接口的使用实例,浅拷贝与深拷贝】
- Comparable接口
- String类型比较
- 多个对象的比较
- Comparator接口
- Cloneable接口
- 浅拷贝
- 深拷贝
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写接口方法
@Override
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方法
那么我们只需要调用就可以了
@Override
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
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>{
@Override
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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
创建一个Person类之后,实现对象的克隆
虽然Person类里面没有clone方法,但是Object类里面有,每一个类都默认继承与Object类,但此时还是报错了,这就需要在Person类中重写clone方法
@Override
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;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Person类的clone也要重写
Person克隆之后,Money也进行克隆,就是深拷贝