调用java.lang.String不可变是正确的吗?

Evg*_*eev 16 java immutability

这个Java教程 说不可变对象在创建后不能改变它的状态.

java.lang.String 有一个领域

/** Cache the hash code for the string */
private int hash; // Default to 0
Run Code Online (Sandbox Code Playgroud)

hashCode()方法的第一次调用时初始化,因此它在创建后更改:

    String s = new String(new char[] {' '});
    Field hash = s.getClass().getDeclaredField("hash");
    hash.setAccessible(true);
    System.out.println(hash.get(s));
    s.hashCode();
    System.out.println(hash.get(s));
Run Code Online (Sandbox Code Playgroud)

产量

0
32
Run Code Online (Sandbox Code Playgroud)

调用Stringimmutable 是否正确?

Sle*_*led 13

更好的定义不是对象不会改变,而是不能观察到它已被改变.它的行为永远不会改变:.substring(x,y)将始终为该字符串同样返回相同的东西equals以及所有其他方法.

该变量在您第一次调用时计算,.hashcode()并在进一步调用时进行缓存.这基本上就是他们在函数式编程语言中所谓的" memoization ".

反射不是真正的"编程"工具,而是元编程(即用于生成程序的编程程序),因此它并不真正重要.它相当于使用内存调试器更改常量值.


Ani*_*Ani 8

"不可变"一词含糊不清,不允许精确定义.

我建议从Eric Lippert的博客中阅读各种不可变性.虽然它在技术上是一篇C#文章,但它与提出的问题非常相关.特别是:

观察不变性:

假设你有一个具有属性的对象,每次你调用一个方法,查看一个字段等,你会得到相同的结果.从调用者的角度来看,这样的对象将是不可变的.但是你可以想象,在幕后,对象正在进行延迟初始化,在哈希表中记忆函数调用的结果等.对象的"胆量"可能完全是可变的.

有什么关系?真正深度不可变的对象根本不会改变它们的内部状态,因此本质上是线程安全的.在幕后可变的对象可能仍然需要具有复杂的线程代码,以便在"同时"在两个线程上调用对象时保护其内部可变状态免于损坏.