gpt4 book ai didi

java - 我们如何使用可变引用来保持类的不可变性

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:07:49 25 4
gpt4 key购买 nike

我知道使我们的类不可变的所有基本规则,但是当有另一个类引用时我有点困惑。我知道是否有集合而不是 Address那么我们可以利用Collections.unmodifiableList(new ArrayList<>(modifiable));然后我们可以让我们的类不可变。但在下面的情况下,我仍然无法理解这个概念。

public final class Employee{
private final int id;
private Address address;
public Employee(int id, Address address)
{
this.id = id;
this.address=address;
}
public int getId(){
return id;
}
public Address getAddress(){
return address;
}
}

public class Address{
private String street;
public String getStreet(){
return street;
}
public void setStreet(String street){
this.street = street;
}
}

最佳答案

嗯,概念是阅读JLS并理解它。 JLS 的第 17 章“线程和锁”描述了内存可见性和同步。 Section 17.5 "Final Field Semantics"描述了 final 字段的内存可见性语义。该部分部分说:

final fields also allow programmers to implement thread-safe immutable objects without synchronization. A thread-safe immutable object is seen as immutable by all threads, even if a data race is used to pass references to the immutable object between threads. This can provide safety guarantees against misuse of an immutable class by incorrect or malicious code. final fields must be used correctly to provide a guarantee of immutability.

The usage model for final fields is a simple one: Set the final fields for an object in that object's constructor; and do not write a reference to the object being constructed in a place where another thread can see it before the object's constructor is finished. If this is followed, then when the object is seen by another thread, that thread will always see the correctly constructed version of that object's final fields. It will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are.

所以你需要:

  1. 使 address 成为最终的和私有(private)的。
  2. 对于任何可变对象,您必须防止外部看到对该对象的引用。

在这种情况下,#2 可能意味着您不能像使用 getAddress() 那样返回对 Address 的引用。 并且您必须在构造函数中创建一个防御性副本。即,复制任何可变参数,并将副本存储在 Employee 中。如果不能制作防御性副本,就真的没有办法让 Employee 不可变。

public final class Employee{
private final int id;
private final Address address;
public Employee(int id, Address address)
{
this.id = id;
this.address=new Address(); // defensive copy
this.address.setStreet( address.getStreet() );
}
public int getId(){
return id;
}
public Address getAddress() {
Address nuAdd = new Address(); // must copy here too
nuAdd.setStreet( address.getStreet() );
return nuAdd;
}

实现 clone() 或类似的东西(复制构造函数)将使复杂类的创建防御对象变得更容易。但是,我认为最好的建议是使 Address 不可变。一旦这样做,您就可以自由地传递它的引用,而不会出现任何线程安全问题。

在这个例子中,注意我NOT必须复制street的值。 Street 是一个字符串,字符串是不可变的。如果 street 包含可变字段(例如整数街道编号),那么我也必须复制 street,依此类推无限。这就是不可变对象(immutable对象)如此有值(value)的原因,它们打破了“无限复制”链。

由于这个问题越来越受欢迎,我还应该提到 Brian Goetz's book, Java 并发实践,这就是我学习这些技术的方式,我基本上是在复述上面那本书。

关于java - 我们如何使用可变引用来保持类的不可变性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34109363/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com