不可变到底是什么意思——也就是说,对象可变或不可变的结果是什么?特别是,为什么Java的字符串是不可变的?

我的理解是StringBuilder类型类似于String的可变等价。什么时候我会使用StringBuilder而不是字符串,反之亦然?


当前回答

java.time

这可能有点晚了,但为了理解什么是不可变对象,请考虑以下来自新的Java 8日期和时间API (Java . Time)的示例。你可能知道,Java 8中的所有日期对象都是不可变的,所以在下面的例子中

LocalDate date = LocalDate.of(2014, 3, 18); 
date.plusYears(2);
System.out.println(date);

输出:

2014-03-18

这将打印与初始日期相同的年份,因为plusYears(2)返回一个新对象,因此旧日期仍然不变,因为它是一个不可变对象。一旦创建,您就不能进一步修改它,日期变量仍然指向它。

因此,该代码示例应该捕获并使用由plusYears调用实例化并返回的新对象。

LocalDate date = LocalDate.of(2014, 3, 18); 
LocalDate dateAfterTwoYears = date.plusYears(2);

date.toString()…2014-03-18 dateAfterTwoYears.toString()…2016-03-18

其他回答

不可改变的意思是不可改变的。字符串对象一旦创建,其数据或状态就不能更改

考虑下面的例子:

class Testimmutablestring{  
  public static void main(String args[]){  
    String s="Future";  
    s.concat(" World");//concat() method appends the string at the end  
    System.out.println(s);//will print Future because strings are immutable objects  
  }  
 }  

让我们考虑一下波纹图,

在这个图中,你可以看到一个新对象被创建为“Future World”。但不改变“未来”。因为字符串是不可变的。s,仍指“未来”。如果你需要给“未来世界”打电话,

String s="Future";  
s=s.concat(" World");  
System.out.println(s);//print Future World

为什么在java中字符串对象是不可变的?

因为Java使用了字符串字面量的概念。假设有5个引用变量,都指向一个对象“Future”。如果一个引用变量改变了对象的值,它将影响到所有的引用变量。这就是为什么字符串对象在java中是不可变的。

不可变对象是指创建后不能修改的对象。一个典型的例子是字符串字面量。

越来越流行的D编程语言通过“不变”关键字具有“不变性”的概念。查看Dr.Dobb关于它的文章http://dobbscodetalk.com/index.php?option=com_myblog&show=Invariant-Strings.html&Itemid=29。它完美地解释了这个问题。

因为公认的答案不能回答所有的问题。11年零6个月后,我不得不给出答案。

有人能解释一下什么是不可变吗?

希望你指的是不可变对象(因为我们可以考虑不可变引用)。

对象是不可变的:iff一旦创建,它们总是表示相同的值(没有任何改变值的方法)。

为什么字符串是不可变的?

尊重上面的定义,这可以通过查看Sting.java源代码来检查。

不可变对象的优点/缺点是什么? 不可变类型有:

更安全,远离虫子。 更容易理解。 而且更愿意改变。

为什么像StringBuilder这样的可变对象应该优先于String,反之亦然?

缩小问题为什么我们在编程中需要可变的StringBuilder ? 它的一个常见用途是将大量字符串连接在一起,就像这样:

String s = "";
for (int i = 0; i < n; ++i) {
    s = s + n;
}

使用不可变字符串,这会产生大量临时拷贝——在构建最终字符串的过程中,字符串的第一个数字(“0”)实际上被复制n次,第二个数字被复制n-1次,依此类推。实际上,做所有这些复制需要花费O(n2)时间,尽管我们只连接了n个元素。

StringBuilder的设计目的是最小化这种复制。它使用了一个简单但巧妙的内部数据结构来避免任何复制,直到最后,当你使用toString()调用来请求最终的String时:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; ++i) {
  sb.append(String.valueOf(n));
}
String s = sb.toString();

获得良好的性能是我们使用可变对象的原因之一。另一个是方便的共享:通过共享一个公共的可变数据结构,程序的两个部分可以更方便地通信。

更多信息请访问:https://web.mit.edu/6.005/www/fa15/classes/09-immutability/#useful_immutable_types

不可变意味着一旦一个对象的构造函数完成执行,该实例就不能被改变。

这很有用,因为这意味着你可以传递对对象的引用,而不用担心其他人会改变它的内容。特别是在处理并发性时,对于永不更改的对象不存在锁定问题

e.g.

class Foo
{
     private final String myvar;

     public Foo(final String initialValue)
     {
         this.myvar = initialValue;
     }

     public String getValue()
     {
         return this.myvar;
     }
}

Foo不必担心getValue()的调用者可能会更改字符串中的文本。

如果你想象一个类似于Foo的类,但是成员是StringBuilder而不是String,你可以看到getValue()的调用者能够改变Foo实例的StringBuilder属性。

还要注意你可能会发现的不同类型的不变性:Eric Lippert写了一篇关于这个的博客文章。基本上,你可以拥有接口是不可变的对象,但在幕后实际可变的私有状态(因此不能在线程之间安全地共享)。

一旦实例化,就不能更改。考虑一个类,它的实例可能用作哈希表或类似的键。查看Java最佳实践。