Java类与线程安全集合不可变

Java类与线程安全集合不可变,java,multithreading,thread-safety,immutability,Java,Multithreading,Thread Safety,Immutability,假设我有以下类: public final class Person { final private String personFirstName; final private String personLastName; final private ConcurrentMap<Double, String> phoneMessages; public Person(String firstname, String lastname) {

假设我有以下类:

public final class Person {

   final private String personFirstName;
   final private String personLastName;
   final private ConcurrentMap<Double, String> phoneMessages;

    public Person(String firstname, String lastname) {
       phoneMessages = new ConcurrentHashMap<Double, String>();
       this.personFirstName = firstname;
       this.personLastName = lastname;
    }

    public void add(Double key, String item) {
        phoneMessages.put(key, item);
    }

    public String getPersonFirstName() {
        return personFirstName;
    }

    public String getPersonLastName() {
        return personLastName;
    }

}
公共最终课程人员{
最终私有字符串personFirstName;
最后一个私有字符串personLastName;
最终私有ConcurrentMap电话消息;
公众人物(字符串名、字符串名){
phoneMessages=新的ConcurrentHashMap();
this.personFirstName=firstname;
this.personLastName=lastname;
}
公共无效添加(双键,字符串项){
phoneMessages.put(键、项);
}
公共字符串getPersonFirstName(){
返回personFirstName;
}
公共字符串getPersonLastName(){
返回personLastName;
}
}
即使我创建了一个带有私有最终线程安全集合的类,我的类是不可变的吗?我猜不是


如果在对象中拥有集合不是正确的做法,那么Java中的正确做法是什么?我将如何设计包含集合的类?

正如其他人所指出的,如何使用类将决定使其不可变是否合适

也就是说,您的
Person
类的这个版本是不可变的:

public final class Person {

   final private  String personFirstName;
   final private  String personLastName;
   final private ConcurrentMap<Double,String> phoneMessages;

    public Person(String firstname, String lastname) {
       this.phoneMessages = new ConcurrentHashMap<Double,String> ();
       this.personFirstName = firstname;
       this.personLastName  = lastname;
    }

    private Person(String firstname, String lastname, ConcurrentHashMap<Double,String> phoneMessages) {
       this.personFirstName = firstname;
       this.personLastName  = lastname;
       this.phoneMessages = phoneMessages;
    }

    public Person add(Double Key, String item){
        ConcurrentHashMap<Double, String> newMap = new ConcurrentHashMap<>(this.phoneMessages);
        newMap.put(Key, item);
        return new Person(this.personFirstName, this.personLastName, newMap);
    }

    public String getPersonFirstName() {
        return personFirstName;
    }

    public String getPersonLastName() {
        return personLastName;
    }

    public Map<Double, String> getPhoneMessages() {
        return Collections.unmodifiableMap(this.phoneMessages);
    }

}
公共最终课程人员{
最终私有字符串personFirstName;
最后一个私有字符串personLastName;
最终私有ConcurrentMap电话消息;
公众人物(字符串名、字符串名){
this.phoneMessages=新的ConcurrentHashMap();
this.personFirstName=firstname;
this.personLastName=lastname;
}
私人(字符串firstname、字符串lastname、ConcurrentHashMap phoneMessages){
this.personFirstName=firstname;
this.personLastName=lastname;
this.phoneMessages=phoneMessages;
}
公众人物添加(双键,字符串项){
ConcurrentHashMap newMap=新ConcurrentHashMap(this.phoneMessages);
newMap.put(键、项);
返回新人员(this.personFirstName、this.personLastName、newMap);
}
公共字符串getPersonFirstName(){
返回personFirstName;
}
公共字符串getPersonLastName(){
返回personLastName;
}
公共映射getPhoneMessages(){
返回Collections.unmodifiableMap(this.phoneMessages);
}
}

请注意,
add
方法返回一个不同的
Person
实例,因此当前的
Person
实例保持不变(不变)。

为什么这不是正确的做法?不是所有的东西都需要是不变的。@JBNizet-我已经等了很长时间了。我在读关于不可变类的书,而我对可变类的印象是否定的!我开始重新思考我的很多代码,这个问题出现了,所以它的设计方式,你会离开它吗?你不会改变什么吗?又一次。关于你的代码我只知道这个类。我不知道你打算用它做什么,它的使用环境,等等。因此,不可能推荐一种设计而不是另一种。你将创建另一个地图,以及使用该地图的另一个人实例。根据定义,不可变对象在创建后可能无法修改。如果我只想返回集合,是否可以返回只读类型的集合?而不是使用地图获取新的Person对象。我想问的是,我是否可以实现一个返回只读集合的getter。你可以使用
Collections.unmodifiableMap
(请参阅我编辑的文章)。但是您最关心的保持不变性的方法应该是
add
,它们可以更改对象的内部状态。为了在这些情况下保持不变性,您必须创建一个新的
Person
实例,并将更改应用于该新实例而不是当前实例。这与
String
上的某些方法的工作原理非常相似(例如
replace
)。