Java 如何使下面的类不可变?

Java 如何使下面的类不可变?,java,immutability,date,Java,Immutability,Date,我知道我需要使日期不可变。然而,我不确定还有什么需要修改以确保类是不变的final public final class Journal { private final Set<Article> edition; private final Date pubDate; public Journal(Article [] contents, Date d) { edition = new TreeSet<Article>();

我知道我需要使日期不可变。然而,我不确定还有什么需要修改以确保类是不变的<已为类及其方法声明了code>final

public final class Journal {
    private final Set<Article> edition;
    private final Date pubDate;

    public Journal(Article [] contents, Date d) {
        edition = new TreeSet<Article>();
        for(int i=0; i <contents.length; i++)
        edition.add(contents[i]);

        pubDate = d;
    }

    public Set<Article> getArticles() {
        return Collections.unmodifiableSortedSet(edition);
    }

    public Date getDate() { return pubDate; }
}   
公共期末课程日志{
私人定稿;
私人最终日期;
公共期刊(第[]条目录,日期d){
版本=新树集();

对于(int i=0;i有几种不变性。如果您想要标准不变性,这意味着每个实例变量都是
final
,并且没有setter。如果您想要深度不变性,那么您的类必须是不变性的,但它的所有实例变量也必须是不变性的。或者,您可以让getter只返回您的副本r实例变量(确保它们在您的类中永远不会更改)。但是,这会带来不小的性能成本,并且会在以后产生技术债务。

我相信您在
java.util.Date
中使用的
Date
类。因此,Date在java中是可变的(不确定原因是什么).因此,您应该返回pubDate的副本

public Date getDate() 
{
 return pubDate.clone();
}
另外,添加了一个不可变的新类。如果您的程序不需要特别的
java.util.Date
,我建议您使用该类


编辑:根据评论日期中的建议#克隆可能会导致问题,因为日期可以被细分。使用
新日期(pubDate.getTime())
复制日期对象。

我能给你的最好建议是使用
即时
(或
本地日期时间
分区日期时间
)代替
日期
,因为
即时
(以及其他
java.time
类)是不可变的。
日期
已过时,不应再使用。但是,如果您需要坚持此代码,则可以进行防御性复制,如下所示:

public Journal(Article [] contents, Date d) {
    // ...
    pubDate = new Date(d.getTime());
}

// ...

public Date getDate() {
    return new Date(pubDate.getTime());
}

请注意,
Date.clone
方法未被使用。这是因为
Date
是非最终的,因此
clone
方法不能保证返回类为
java.util.Date
的对象,它可能返回专门设计的不受信任子类的实例恶意。

您需要返回
Date
对象的副本,否则您可以使用
getDate()返回的对象对其进行更改
。将
Date
更改为
Instant
。当您将任何对象传递给类时,最好将其制作一个防御性副本,这样,如果原始对象被更改,则不会影响类。当返回对象时,出于相同的原因返回副本。取决于您何时应该执行其中一项或另一项操作,或两者都取决于对象的性质f应用程序。@Thilo我知道Date现在是遗留代码,但感谢您指出它,因为我刚刚阅读了Instant的属性。我强烈建议您使用
clone
方法。有关详细信息,请参阅why@lealceldeiro我同意你的观点,我们不应该在非期末课上使用克隆。谢谢你的建议。嗨,这是我想要的ad,虽然我也忘了防御性地复制构造函数。我不知道克隆,但很高兴你强调了为什么不使用它。谢谢你。@JayG,不客气:)请记住,如果答案符合你的需要,请投票(或者标记为接受)。