You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中String与Date对象的深拷贝差异及Date深拷贝实现

解答你的Java对象拷贝问题

1. Java中String对象与Date对象的深拷贝差异

咱们得从不可变性和可变性这个核心点说起,这是两者拷贝逻辑差异的根源:

  • String对象:String是Java的不可变类,一旦创建就没法修改内部的字符序列。不管是直接赋值String s2 = s1还是用其他方式“拷贝”,本质都是共享同一个对象引用,但因为String不可变,你永远没法通过原引用修改对象内容——这种引用共享的表现和深拷贝几乎一样,但实际上并没有创建新的String对象(除非你主动调用new String(s1),但这完全没必要,不可变性已经保证了引用共享的安全性)。
  • Date对象:Date是可变类,内部持有一个long类型的时间戳,还提供了setTime()这类修改方法。浅拷贝(比如直接赋值Date d2 = d1)只会复制引用,修改原Date的时间戳会直接影响拷贝后的对象;而深拷贝必须创建全新的Date实例,让两个对象各自持有独立的时间戳,修改其中一个不会波及另一个。

2. 为学生类的birthDate创建深拷贝,以及与其他属性的差异

假设你的学生类结构大致是这样:

class Student {
    private String name;
    private int age;
    private Date birthDate;
    // 构造器、getter、setter省略
}

实现birthDate的深拷贝

有两种常用的可靠方式:

  • 方式一:利用Date自带的clone()方法(Date已经实现了Cloneable接口):
    // 在学生类的拷贝逻辑中
    Date clonedBirthDate = (Date) this.birthDate.clone();
    
  • 方式二:通过Date构造器,基于原对象的时间戳创建新实例:
    Date clonedBirthDate = new Date(this.birthDate.getTime());
    

与name、age的拷贝差异

  • age(数值类型):int是基本数据类型,拷贝时直接复制值,不存在引用共享的问题——修改原对象的age,拷贝后的对象age完全不受影响,这本身就是“深拷贝”的效果,不需要额外处理。
  • name(String类型):因为String不可变,直接赋值clonedName = this.name就足够安全。就算原对象后续重新给name赋值(比如student.setName("NewName")),拷贝对象的name依然指向原来的String实例,不会被修改——这是因为赋值只是让原对象的name引用指向了新的String,而非修改原有String的内容。
  • birthDate(Date类型):Date是可变对象,必须主动创建新实例才能实现深拷贝,否则浅拷贝会导致原对象和拷贝对象共享同一个Date引用,修改其中一个的时间会直接影响另一个。

3. 你的克隆示例是否属于深拷贝?

仅从你给出的输出:

OUTPUT Original Date:Mon Jan 05 00:00:00 IST 2018 Cloned Date:Mon Jan 05 00:00:00 IST 2018 – adding additional Info...

没法直接判定是不是深拷贝,关键要看修改原Date对象后,克隆对象的时间是否会跟着变化:

  • 如果修改原Date的时间(比如调用originalDate.setTime(...)),克隆的Date依然保持Mon Jan 05的时间,那就是深拷贝;
  • 如果克隆的Date时间也变成了修改后的数值,那说明只是浅拷贝(只是复制了引用,两个变量指向同一个Date对象)。

举个直观的例子,如果你的克隆代码是下面这样,那就是深拷贝:

Date original = new Date(1515090600000L); // 对应Mon Jan 05 2018
Date cloned = (Date) original.clone();
original.setTime(1515177000000L); // 修改为Tue Jan 06 2018
System.out.println("Original Date:" + original);
System.out.println("Cloned Date:" + cloned);
// 此时克隆对象的输出还是Mon Jan 05,说明是深拷贝

如果你的代码只是Date cloned = original;,那修改原对象后,克隆对象的时间也会变成Tue Jan 06,这就是浅拷贝。

4. 将克隆代码整合进自定义类

要给自定义的Student类实现完整的深拷贝,常规做法是让类实现Cloneable标记接口,并重写clone()方法:

class Student implements Cloneable {
    private String name;
    private int age;
    private Date birthDate;

    // 构造器、getter、setter

    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 先调用父类clone()完成基本类型和不可变类型的拷贝
        Student clonedStudent = (Student) super.clone();
        // 对可变的Date对象单独做深拷贝
        clonedStudent.birthDate = (Date) this.birthDate.clone();
        // 也可以用构造器方式:clonedStudent.birthDate = new Date(this.birthDate.getTime());
        return clonedStudent;
    }
}

使用时可以这样调用:

try {
    Student originalStudent = new Student("Alice", 20, new Date());
    Student clonedStudent = (Student) originalStudent.clone();
} catch (CloneNotSupportedException e) {
    e.printStackTrace();
}

注意几点:

  • 必须重写clone()方法,否则默认调用Object的clone()只会做浅拷贝;
  • Cloneable是标记接口,没有任何方法,只是告诉JVM这个类允许被克隆;
  • 如果你不想让调用者处理CloneNotSupportedException,也可以封装一个自定义的copy()方法,在内部捕获异常,让调用更友好。

内容的提问来源于stack exchange,提问作者Vinod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 07:15:03