【问题标题】:Java Class Immutable with Thread Safe Collection具有线程安全集合的 Java 类不可变
【发布时间】:2015-07-05 01:23:01
【问题描述】:

假设我有以下课程:

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;
    }

}

即使我创建了一个具有私有最终线程安全集合的类,我的类是不可变的吗?我的猜测是否定的。

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

【问题讨论】:

  • 为什么不是正确的做法?并非所有东西都必须是不可变的。
  • @JBNizet - 我等待阅读这些话的时间最长。我正在阅读关于不可变类的内容,而我对可变类的印象是不!我开始重新考虑我的很多代码,然后出现了这个问题,所以它的设计方式,你会离开它吗?你不会改变什么?
  • 再次。我只知道你的代码是这个类。我不知道你打算用它做什么,它的使用环境等等。所以不可能推荐一种设计而不是另一种。
  • 您将创建另一个地图,并使用该地图创建另一个 Person 实例。根据定义,不可变对象在创建后不得修改。

标签: java multithreading thread-safety immutability


【解决方案1】:

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

也就是说,这个版本的 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);
    }

}

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

【讨论】:

  • 如果我只想返回集合,我可以返回只读类型的集合吗?而不是使用地图获取新的 Person 对象。我可以实现一个返回只读集合的​​ getter 就是我要问的。
  • 您可以为此使用Collections.unmodifiableMap(请参阅我编辑的帖子)。但是你最关心的保持不变性应该是像add 这样改变对象内部状态的方法。为了在这些情况下保持不变性,您必须创建一个新的 Person 实例并将更改应用于该新实例而不是当前实例。这与String 上的某些方法的工作方式非常相似(例如replace)。
猜你喜欢
  • 2013-07-06
  • 1970-01-01
  • 2019-02-10
  • 2011-10-03
  • 2015-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多