You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 17:09:53