关于ScopedValue不可变性的疑问:仅引用不可变而非对象本身?
关于ScopedValue不可变性的疑问与解答
我在Windows系统上使用Oracle JDK 20与Eclipse 2023-03测试ScopedValue。根据资料,ScopedValue应具备不可变性,但我的测试代码却呈现出可变的表现。
测试代码如下:
package demoJava20; import jdk.incubator.concurrent.ScopedValue; class User { String name; }; public class ExampleScopedValues { public final static ScopedValue<User> LOGGED_IN_USER = ScopedValue.newInstance(); public static void main(String[] args) { User loggedInUser = new User(); loggedInUser.name = "ABC"; ScopedValue.where(LOGGED_IN_USER, loggedInUser, () -> f1()); // value will be available through f1 } private static void f1() { User user = LOGGED_IN_USER.get(); System.out.println("In f1 user = " + user.name); user.name = "DEF"; f2(); } private static void f2() { User user = LOGGED_IN_USER.get(); System.out.println("In f2 user = " + user.name); } }
运行后输出:
In f1 user = ABC
In f2 user = DEF
代码中成功将User对象的name属性从ABC修改为DEF,且f2能读取到修改后的值。请问是不是仅ScopedValue的对象引用不可变(无set方法),而对象本身是可变的?
是的,你的理解完全正确。ScopedValue的不可变性指的是它绑定的对象引用不可更改——一旦通过ScopedValue.where()绑定了某个对象实例,在当前作用域内就无法修改这个绑定关系(没有提供类似set的方法来替换引用)。但被绑定的对象本身如果是可变类型(比如你的User类),其内部状态是可以被修改的,这种修改会被同一作用域内的所有代码看到,就像你测试里f1修改name后f2能读到新值一样。
如果想要避免这种内部状态被修改的情况,应该使用不可变的对象类型,比如把User类改成不可变:
class User { private final String name; public User(String name) { this.name = name; } public String getName() { return name; } }
这样就无法修改name属性,从而保证整个ScopedValue绑定的内容真正不可变。
内容的提问来源于stack exchange,提问作者Gonen I
相关产品推荐
相关产品推荐

