最快克隆GregorianCalendar的方法是什么?

28

我正在尝试制作一个对象的深度副本,其中包括一个GregorianCalendar实例。我总是谨慎使用clone(),并且它似乎没有在这里被重写,因此我只能逐个字段地进行复制。理想情况下,会有一个复制构造函数,我可以像这样使用:

GregorianCalendar newCalendar = new GregorianCalendar(oldCalendar);

很不幸,我在API中找不到这样的功能,而且一直在尝试弄清楚我需要哪些字段才能得到完全相同的副本。因此,要复制其中一个日历,您会如何操作?我是否错过了某些简单的快捷方式?

4个回答

41

java.util.Calendar 已经重写了 clone() 方法并且可以正常工作,所以请使用它。此外,Calendar 没有深层次的数据层级结构,其数据主要是 int 类型。

如果整个数据层次结构实现了 Serializable 接口,您可以调用 SerializationUtils.clone(…)(从 Apache commons-lang 中)对任何对象进行深拷贝。


我没有很清楚为什么我要避免使用clone()方法。在这种情况下,我只是遵循Joshua Bloch的建议,进行防御性拷贝。由于clone()可能会调用子类的clone()方法,所以我可能会得到一个非干净的副本。在我的情况下有点学术性,但这就是我为什么避免使用它的原因。 - wds
正如我所说,日历中的数据不受此问题影响 - 其所有数据都是基本类型。而且Calendar中的克隆方法也能正常工作。 - Bozho
他的观点是,你可以构建一个子类,保留对原始日历实例的引用并将其保留下来。如果所有的setter都在原始实例中设置值而不是新实例中,那么你的“深度”复制现在将被破坏。 - wds
1
你也可以像这样做:Calendar cal_copy = Calendar.getInstance(); cal_copy.setTimeInMillis(cal.getTimeInMillis()); - Christopher Masser

2

太长不读

使用现代的java.time类来替换GregorianCalendar

GregorianCalendar.from(                     // Convert from modern object to legacy class object.
    myGregorianCalendar.toZonedDateTime()   // Convert from legacy to modern.
)                                           // Returns a new `GregorianCalendar` object.

更好的做法是完全停止使用 GregorianCalendar,并改用 ZonedDateTime

ZonedDateTime

可怕的 GregorianCalendar 类早在多年前就被 JSR 310 中定义的 java.time 类所取代。具体而言,被 ZonedDateTime 类所替代。
您可以使用添加到旧类中的新 to…/from… 方法进行转换。
ZonedDateTime zdt = myGregorianCalendar.toZonedDateTime() ;

走另一条路。
GregorianCalendar myGregorianCalendar = GregorianCalendar.from( zdt ) ;

具体回答您的问题,将这两个转换结合起来可以得到另一个GregorianCalendar对象。
GregorianCalendar gc = GregorianCalendar.from( myGregorianCalendar.toZonedDateTime() ) ;

关于 java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了老旧的 遗留 日期时间类,如 java.util.DateCalendarSimpleDateFormat

要了解更多,请参见Oracle教程。并在Stack Overflow上搜索许多示例和解释。规范是JSR 310Joda-Time项目现在处于维护模式,建议迁移到java.time类。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。无需字符串,也无需java.sql.*类。
从哪里获取java.time类? 该项目是ThreeTen-Extra,它扩展了java.time的附加类。这个项目是用来测试可能未来添加到java.time中的类的地方。你可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter更多

1
具体而言,复制日历的最快代码行是:
GregorianCalendar newCalendar = (Calendar)(oldCalendar.clone());

最好将其转换为 GregorianCalendar。GregorianCalendar newCalendar =(GregorianCalendar)oldCalendar.clone(); - Yetti99

-8

嗯,clone() 真烂。

这难道很难吗?你只需要设置三个东西,我相信,时间、时区和语言环境。所有这些字段都有 getter 和 setter。编写一个简单的实用方法来返回一个副本不就行了吗?


我不明白,既然Calendar和GregorianCalendar都实现了自定义的克隆方法,为什么不能使用它们呢? - Jane Panda
2
硬度谬论。好的程序员是懒惰的。 - Jonas Byström

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接