如何防止类实例被更改

How to protect class instance against alteration

提问人:reda Sabbane 提问时间:9/29/2023 最后编辑:Mark Rotteveelreda Sabbane 更新时间:9/30/2023 访问量:107

问:

如何修改代码的主体(可以包括构造函数的主体)以保护 Person 实例不被更改:一旦创建了 Person,就不可能修改它。

import java.util.Date;
 
class Person {
 
    private String name;
    private Date birthDate;
 
    /**
     * Creates a Person with the given name and birth​​​​​​​​​‌​​​‌‌​​‌‌​​​​​​​‌​​​‌ date.
     */
    public Person(String name, Date birthDate) {
        this.name = name;
        this.birthDate = birthDate;
    }
 
    public String getName() {
        return name;
    }
 
    public Date getBirthDate() {
        return birthDate;
    }
}

我知道不可变类的约束都存在于这个类中:

  1. 所有字段都是私有的,
  2. 我们没有字段的 setter,
  3. 我们没有带有 setters 的对象的字段

但是,我不知道我必须添加什么来保护 Person,一旦创建了 Person,就应该无法修改它。

Java 不可变性

评论

2赞 9/29/2023
这回答了你的问题吗?使 Java 对象不可变
5赞 Holger 9/29/2023
我们无法读懂提问者的心思。也许他们希望你回答你必须添加到字段中,也许,他们希望你认识到这是一个可变对象,因此,为了防止你的类被修改,构造函数和 getter 必须创建对象的防御副本。更好的方法是将类型更改为不仅不可变,而且可以解决与此处使用相关的一系列其他问题。然后,只需更改类即可解决更多潜在问题。finalDateDateLocalDateDaterecord Person(String name, LocalDate birthDate) {}
2赞 Jesper 9/29/2023
你已经知道答案了。“不可变”的意思正是你所问的:当一个类是不可变的时,这意味着该类的对象在创建后不能被修改。所以你只需要做你自己提到的事情:1.将所有字段设为私有,2.不要有setter方法。另外:使类本身。final
2赞 Andy Turner 9/29/2023
@Jesper并且不要从 getter 返回实例的可变对象。
0赞 reda Sabbane 9/30/2023
坦克你这么多

答:

2赞 WJS 9/29/2023 #1

一种方法是使用 定义不可变类的 。您仍然可以重写以修改对象自身的显示方式。recordtoString()

对于使用 getter 的类定义,请将字段设为私有字段和 final。对于那些在设计上不是不可变的字段,请执行所谓的 .对于数组和集合等对象尤其如此。可能还需要对这些数组或集合的单个单元进行深度复制。defensive copying

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

注意:已过时。从 java.time 包中使用。由于是不可变的,因此您可以安全地返回实例。DateLocalDateLocalDate

0赞 Reilas 9/30/2023 #2

"...我不知道我必须添加什么来保护 Person,一旦创建了 Person,就应该无法修改它。..."

你所拥有的是正确的。

(可选)不要使用构造函数方法,而应使用静态方法

class Person {

    private String name;
    private Date birthDate;

    /**
     * Creates a Person with the given name and birth​​​​​​​​​‌​​​‌‌​​‌‌​​​​​​​‌​​​‌ date.
     */
    private Person(String name, Date birthDate) {
        this.name = name;
        this.birthDate = birthDate;
    }

    static Person get(String name, Date birthDate) {
        return new Person(name, birthDate);
    }

    public String name() {
        return name;
    }

    public Date birthDate() {
        return birthDate;
    }
}

评论

0赞 WJS 9/30/2023
正如我所理解的那样,他们希望使 Person 类不可变。使用您当前的 getter 对于某人仍然可以修改实例。在此示例中,返回的 from 可以更改,因为 的实例不是不可变的。DatePersonDatebirthDate()Date
0赞 reda Sabbane 9/30/2023
非常感谢你,请尝试您的解决方案并搜索有关不可变类的更多信息