【java比较方法、浅拷贝、深拷贝】

希望本博客对你有所帮助。(能帮助一点点我就非常开心!!!)

Comparable接口

举例:我们这里写一个Student类,里面包含两个成员变量(姓名和年龄)


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 "Test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

当我们对自己自定义的类进行比较,会发现代码报错!因为这些操作符只能比较基本数据类型(byte、short、int、long、float、double)的数值。

public class Test {
    public static void main(String[] args) {
        Student student1=new Student("zhangsan ",6);
        Student student2=new Student("lisi ",8);
        System.out.println(student1>student2);
    }
}

在这里插入图片描述

因此这里就引出了 Comparable接口,当比较自定义类的成员变量,需要重写Comparable接口中的compareTo方法。

//Student.java
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 int compareTo(Student o) {
        return this.age-o.age;
    }
    
    @Override
    public String toString() {
        return "Test{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

//Test.java
public class Test {
    public static void main(String[] args) {
        Student student1=new Student("zhangsan ",6);
        Student student2=new Student("lisi ",8);
        System.out.println(student1.compareTo(student2));//-2
    }
}

这个重写的compareTo方法是通过年龄进行比较的,你也可以通过name进行比较,那么compareTo方法的代码应该是:return this.name.compareTo(o.name);(这里通过字符串比较大小是和C语言中是一样的)

这里值得注意的是怎样实现Comparable接口,Comparable<“T”>(<“T”>是泛型,后续会为您详细解释,这里只需要知道即可)当你要比较那个自定义类,“T”就改为你自定义类的类名。如这里比较的是“Student”类,因此Comparable<“Student”>。

在这里插入图片描述
以上是单个类的实例比较,那么如果我要实现多个类比较,应该怎么办呢?

这里我们可以通过数组进行多个类的比较

public class Test {
    public static void main(String[] args) {
        Student[] students=new Student[4];
        students[0]=new Student("zhangsan ",6);
        students[1]=new Student("lisi ",8);
        students[2]=new Student("wangwu ",10);
        students[3]=new Student("laoliu ",9);
        System.out.println("排序前"+Arrays.toString(students));
        Arrays.sort(students);
        System.out.println("排序后"+Arrays.toString(students));
    }
}

运行结果:
在这里插入图片描述

这里的 Arrays.sort()方法也是根据你重写的compareTo方法进行比较排序的。如果你需要逆序比较,只需要把return this.age-o.age;改为return o.age-this.age;

总结:

一个自定义的类中有且只能有重写的一个compareTo方法,不会出现多个compareTo方法。此时,compareTo方法的缺点就体现出来了,局限性太大了(compareTo 方法只支持一种比较方式)!!!因此这里就引出了Comparator 接口允许你为自定义类实现多个比较逻辑

Comparator 接口

还是以上面的Student为例进行演示。

//NameComparator
import java.util.Comparator;

public class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}

这是我重写的Comparator接口中的compare()方法(通过name进行比较)。

public class Test {
    public static void main(String[] args) {
        Student[] students=new Student[4];
        students[0]=new Student("zhangsan ",6);
        students[1]=new Student("lisi ",8);
        students[2]=new Student("wangwu ",10);
        students[3]=new Student("laoliu ",9);
        System.out.println("排序前"+Arrays.toString(students));
        NameComparator nameComparator=new NameComparator();
        Arrays.sort(students,nameComparator);
        System.out.println("排序后"+Arrays.toString(students));
    }
}

运行结果:
在这里插入图片描述

    public static void main(String[] args) {
        Student[] students=new Student[4];
        students[0]=new Student("zhangsan ",6);
        students[1]=new Student("lisi ",8);
        students[2]=new Student("wangwu ",10);
        students[3]=new Student("laoliu ",9);
        System.out.println("排序前"+Arrays.toString(students));
        NameComparator nameComparator=new NameComparator();
        int ret=nameComparator.compare(students[0],students[2]);
        System.out.println(ret);
    }

这里你还可以通过对象的引用,来调用Comparator接口中的Compare()方法。

//AgeComparator
public class AgeComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age-o2.age;
    }
}
//Test.java
public class Test {
    public static void main(String[] args) {
        Student[] students=new Student[4];
        students[0]=new Student("zhangsan ",6);
        students[1]=new Student("lisi ",8);
        students[2]=new Student("wangwu ",10);
        students[3]=new Student("laoliu ",9);
        System.out.println("排序前"+Arrays.toString(students));
        NameComparator nameComparator=new NameComparator();
        AgeComparator ageComparator=new AgeComparator();
        Arrays.sort(students,nameComparator);
        System.out.println("name排序后"+Arrays.toString(students));
        Arrays.sort(students,ageComparator);
        System.out.println("age排序后"+Arrays.toString(students));
    }
}

运行结果:
在这里插入图片描述

通过使用 Comparator,你可以定义多个不同的排序逻辑,而无需修改原始类的源代码。

equals方法

equals() 方法是 Object 类的一个方法,用于比较两个对象的“内容”是否相等,而不仅仅是它们的引用(即内存地址)是否相同。并且重写之后会发现equals()方法返回的是boolean类型。

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

拷贝

拷贝的注意事项:

  1. 先实现Cloneable接口。

public interface Cloneable {
}

Cloneable接口是空接口,作用:标记当前自定义类是可以拷贝的。

在这里插入图片描述

2.再重写clone()方法。

这里需要注意两点:一、因为object是所有类的父类,所以这里在实例化的时候需要向下转型;二、重写clone()方法会抛出异常,所以在main函数调用此方法时,也需要抛出异常。

在这里插入图片描述

浅拷贝

浅拷贝会创建一个新对象,这个新对象有着原始对象属性值的一份精确拷贝。如果属性是基本数据类型,拷贝的就是基本数据类型的值;如果属性是引用数据类型,拷贝的就是内存地址,因此如果属性指向的对象被修改,那么原始对象和新对象都会受到影响,因为它们指向的是同一个对象。

//Writer.java
class Writer implements Cloneable{
    public String author="张三";
@Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//Book.java
public class Book implements Cloneable {
    public String name="查理九世";
    public double money=9.9;
    public Writer writer=new Writer();

    public Book() {
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
//Test.java
public class Test {
    public static void main(String[] args) throws CloneNotSupportedException{
        Book book1=new Book();
        Book book2=(Book) book1.clone();
        System.out.println("修改前"+book1.writer.author);
        System.out.println("修改前"+book2.writer.author);
        book1.writer.author="李四";
        System.out.println("修改后"+book1.writer.author);
        System.out.println("修改后"+book2.writer.author);
    }
}

运行结果:
在这里插入图片描述

深拷贝

深拷贝会创建一个新对象,并且递归地复制对象中引用的其他对象,直到这些对象都变为基本类型为止。这样,原始对象和新对象之间就没有任何关联了,修改新对象的任何属性(包括引用类型的属性)都不会影响到原始对象。

    @Override
    protected Object clone() throws CloneNotSupportedException {
       Book tmp=(Book)super.clone();
       tmp.writer=(Writer) this.writer.clone();//调用所写Writer类中的clone()方法,将新对象赋值给tmp对象的writer成员变量;
       return tmp;
    }

深拷贝就和浅拷贝重写的clone()方法不一样,其他都一样!
运行结果:
在这里插入图片描述

总结:深拷贝和浅拷贝是根据代码区实现的!!!
较为容易理解:
如果重新开辟了空间拷贝过去了,那就是深拷贝,
如果没有还是指向原来的空间,那就是浅拷贝。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值