Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

06-01 1529阅读

1.比较

1.1 基本数据类型的比较

Java中基本数据类型可以通过 == , > ,

还可以使用其对应的包装类调用equals方法来比较

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

1.2引用类型的比较

我这里创建了一个自定义类student

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

Object类自带的equals方法实际上和==差不多,用更是会直接报错

既然如此,该如何实现对象之间的比较呢?

以下会展示三种方法

1.3 对象的比较

1.3.1 重写Object中的equals方法

重写之后就可以调用自己的equals方法

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

1.3.2 实现Comparable接口

实现Comparable接口,然后在该类中重写compareTo方法

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

因为在StudengA内部重写compareTo方法,所以以后比较StudentA类型的大小,只能比较它的id大小(除非改变StudentA内部的compareTo方法),对类的侵入性较强

1.3.3 提供比较器(Comparator)

创建一个类来实现Comparator接口,并且重写接口里的compare方法

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

相较于实现Comparable接口,比较器对类的侵入性没那么强,可以按照提供的比较器来实现不同的比较逻辑

1.4 为什么要实现对象的比较?

因为在优先级队列/TreeMap(举的例子)中,如果要往里面添加元素,则添加的元素必须是可比较的,否则会报错,下面以TreeMap为例

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

1.5 三个比较方式对比

1.Object.equals:因为所有类都是继承自 Object 的,所以直接覆写即可,不过只能比较相等与否

2.Comparable.compareTo:需要手动实现接口,侵入性比较强,但一旦实现,每次用该类都有顺序,属于内部顺序

3.Comparator.compare:需要实现一个比较器对象,对待比较类的侵入性弱

2.深浅拷贝(2025年5月11日新增)

在Java SE(5)——数组中介绍了Arrays工具类,调用其中的copyOf()方法可以完成对数组的拷贝

那么,如果想要对一个对象进行拷贝又应该怎么样实现呢?

public class CopyPerson {
    public String name;
    public int age;
    public int score;
    //
    public CopyPerson(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}
public class Copy {
    public static void main(String[] args){
        CopyPerson person1 = new CopyPerson("张三",18,98);
        CopyPerson person2 = person1;
        System.out.println(person2);
    }
}

运行结果:

Person{name=‘张三’, age=18, score=98}

在上述代码中,仅看运行结果貌似是完成了一个对象的拷贝,但实际上只是将原对象的地址赋值给新的引用而已,在堆中仍然只存在一份对象

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

下面就讲解如何将对象完整地在堆中拷贝一份

2.1 浅拷贝

在Java中有专门拷贝对象的方法:Object类中的clone方法(如下)。

protected native Object clone() throws CloneNotSupportedException;

该clone()方法是由native修饰,表示该方法的具体实现是使用C/C++写的,我们无法查看方法的内部代码。因为Object类默认是所有类的父类,所以如果要使用该方法只需要在子类中重写就行了

修改后代码如下:

public class ShallowPerson implements Cloneable {
    public String name;
    public int age;
    public int score;
    //
    public ShallowPerson(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class ShallowClone {
    //浅拷贝
    public static void main(String[] args) throws CloneNotSupportedException {
        ShallowPerson person1 = new ShallowPerson("张三",18,98);
        ShallowPerson person2 = (ShallowPerson) person1.clone();
        System.out.println(person1);
        System.out.println(person2);
        //修改person2的age
        person2.age = 20;
        System.out.println(person1);
        System.out.println(person2);
    }
}

运行结果:

Person{name=‘张三’, age=18, score=98}

Person{name=‘张三’, age=18, score=98}

Person{name=‘张三’, age=18, score=98}

Person{name=‘张三’, age=20, score=98}

根据运行结果可知,修改person2中的age值并没有影响person1中的age值,所以可以判定person1和person2指向的是两个对象Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

注意:被拷贝的类必须实现Cloneable接口,这个接口中没有任何方法,实现该接口的类也不会重写任何方法,但是会被声明为可拷贝的(Cloneable)。换言之,实现Cloneable接口后会被赋予可拷贝的权限,如果不实现该接口直接重写并调用clone()方法会抛出CloneNotSupportedException异常(不支持拷贝)

问题一:上述代码中,子类重写的clone()方法貌似并没有改变内部逻辑,依然是调用父类的clone()方法,那么重写的意义是什么?

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

对比子类和Object中的clone()方法,唯一的区别就是访问限定修饰符,那么把protected修改为public的作用是什么呢?

被protected修饰的成员,在同一个包中可以被任意的类访问,在不同的包中只能在子类中访问。在不重写clone()方法的情况下,ShallowPerson只能在自己的内部调用clone()方法,而无法在ShallowClone中通过ShallowPerson的引用来访问clone()方法(protected成员的访问权限是基于类层级结构(继承)和包结构的,而不是对象的引用)

问题二:当被拷贝的类中存在其他引用变量时(如自定义类),上述的拷贝还能顺利完成吗?

拷贝不彻底,位置关系图如下:Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

要想把Money对象也进行拷贝,仅需要进行深拷贝操作

2.2 深拷贝

public class DeepPerson implements Cloneable {
    public String name;
    public int age;
    public int score;
    public Money money;
    //
    public DeepPerson(String name, int age, int score,int money) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.money = new Money(money);
    }
    @Override
    public String toString() {
        return "DeepPerson{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                ", money=" + money +
                '}';
    }
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
//Money类中也实现Cloneable接口并重写clone()方法
public class Money implements Cloneable {
    public int money;
    //
    public Money(int money) {
        this.money = money;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "Money{" +
                "money=" + money +
                '}';
    }
}
public class DeepClone {
    public static void main(String[] args) throws CloneNotSupportedException {
        DeepPerson deepPerson1 = new DeepPerson("李四",20,100,25000);
        DeepPerson deepPerson2 = (DeepPerson) deepPerson1.clone();
        System.out.println(deepPerson1);
        System.out.println(deepPerson2);
        deepPerson2.money = new Money(26000);
        System.out.println(deepPerson1);
        System.out.println(deepPerson2);
    }
}

运行结果:

Java Collection(5)——比较(数据/对象)&深浅拷贝(对象)

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们。

相关阅读

目录[+]

取消
微信二维码
微信二维码
支付宝二维码