Som*_*guy 73 java string immutability
我一直在研究Java String.以下问题基于以下帖子
Java String是java中特殊
的String不可变性
不可变性:现在,通过不变性,String类被设计为公共池中的值可以在其他位置/变量中重用.如果String
被创建为, 则这很好
String a = "Hello World!";
但是,如果我创建String之类的
String b = new String("Hello World!");
为什么这也是不变的?(或者是吗?).由于这有一个专用的堆内存,我应该能够修改它而不影响任何其他变量.因此,通过设计,还有其他任何原因,为什么String
整体被认为是不可改变的?或者我的上述假设是错误的?
我想问的第二件事是关于常见的字符串池.如果我创建一个字符串对象为
String c = "";
是在池中创建的空条目?
这些帖子上已经有帖子吗?如果是这样,有人可以分享链接吗?
Ste*_*n C 105
new String()
是一个表达式,它产生一个String
...而a String
是不可变的,无论它是如何产生的.
(询问是否new String()
可变是荒谬的.它是程序代码,而不是价值.但我认为这不是你真正的意思.)
如果我创建一个字符串对象,就像
String c = "";
在池中创建的空条目一样?
是; 也就是说,为空字符串创建一个条目.一个空的没什么特别的String
.
(为了迂腐,在""
代码执行之前很久就创建了get的pool条目.实际上,它是在代码加载时创建的......或者甚至可能早于此代码.)
所以,我想知道新的堆对象是否也是不可变的,...
是的.但不变性是String对象的基本属性.所有String
对象.
你看,String
API根本没有提供任何改变方法String
.所以(除了使用反射的一些危险和愚蠢的1个技巧),你不能改变a String
.
如果是的话,目的是什么?
Java String
被设计为不可变类的原因是简单性.如果核心字符串类提供不可变的接口,它可以更容易地编写正确的程序,并读取/推理其他人的代码.(至少,正如我所理解的那样,这就是这个设计决策的基本原理.)
通过答案,我认为其他对同一变量的引用是其中一个原因.如果我理解这一点,请告诉我.
不,它比这更重要.简单地说,所有String
对象都是不可变的.理解这一点并不需要复杂的特殊情况推理.它只是>>是<<.
为了记录,如果你想在Java中使用可变的"类似字符串"的对象,你可以使用String
或StringBuilder
.但这些是String的不同类型.
1 - 这些技巧(IMO)危险和愚蠢的原因是它们会影响通过字符串池可能由应用程序的其他部分共享的字符串的值.这可能会导致混乱......下一个维护代码的人几乎没有机会追踪.
Nar*_*hai 42
1)简短回答是肯定的,new String()
也是不可改变的.
因为每一个可能的可变操作(比如replace
,toLowerCase
您执行上etcetra)String
不影响原有的 String
实例,并返回一个新的实例.
你可以在Javadoc中查看String
.暴露的每个public
方法String
都返回一个新String
实例,并且不会改变您调用该方法的当前实例.
这在多线程环境中非常有用,因为每次传递或共享时都不必考虑可变性(有人会更改值)String
.String
很容易成为最常用的数据类型,因此设计师们祝福我们所有人不要每次都考虑可变性并为我们带来很多痛苦.
由于不可变性属性,字符串的内部池是可能的,因为当在其他某个地方需要相同的String值时,则返回该不可变引用.如果String
本来是可变的那么就不可能String
像这样分享s来节省内存.
字符串的不可变性不是因为汇集,而是不可变性带来了更多的好处.
字符串实习或池化是Flyweight设计模式的一个示例
2)是的,它会像其他任何String
一样被实习,因为空白String
也String
和其他String
实例一样多.
参考文献:
chr*_*ke- 18
String
无论对象是如何构造的,Java库都围绕任何对象不可变的约束进行了大量优化.即使您创建b
使用new
其他代码,您传递实例将把值不变.这是Value Object模式的一个示例,并且所有优点(线程安全,无需进行私有复制)都适用.
空字符串""
是一个合法的String
对象,就像其他任何东西一样,它恰好没有内部内容,并且由于所有编译时常量字符串都被实现,我几乎可以保证某些运行时库已经将它添加到了池.
Cub*_*bic 14
1)不可变部分不是因为池; 它只是让游泳池成为可能.字符串通常作为参数传递给其他函数,甚至与其他线程共享; 使字符串不可变是一种设计决策,使在这种情况下的推理更容易.所以是的 - String
无论你如何创建它们,Java中的s总是不可变的(请注意,在java中可能有可变字符串 - 只是没有String
类).
2)是的.大概.我实际上并不完全确定,但情况确实如此.
字符串是不变的; 它们的值在创建后无法更改.
然后再次:
字符串缓冲区支持可变字符串.因为String对象是不可变的,所以可以共享它们.
一般来说:"所有原始"(或相关)对象都是不可变的(请接受我缺乏形式主义).
Stack Overflow上的相关文章:
关于对象池:对象池是一个java优化,它与不可变也无关.
这不是你的问题的严格答案,但如果你的问题背后是希望有可操作的可变字符串,你应该检查出StringBuilder
类,它实现了许多完全相同的方法,String
但也添加了方法改变当前的内容.
一旦你以一种你满足它的方式构建你的字符串,你只需调用toString()
它就可以将它转换为普通的String
,你可以传递给库例程和其他只带String
s的函数.
此外,双方StringBuilder
并String
实现了CharSequence
接口,所以如果你想编写自己的代码功能,可以同时使用可变和不可变的字符串,你可以宣布他们采取的任何CharSequence
物体.
实际上,这是另一种方式.
[...]
String
该类的设计使公共池中的值可以在其他位置/变量中重用.
不,String
该类是不可变的,因此您可以安全地引用它的实例,而不必担心它从程序的其他部分被修改.这就是为什么首先可以汇集的原因.
所以,考虑一下:
// this string literal is interned and referenced by 'a'
String a = "Hello World!";
// creates a new instance by copying characters from 'a'
String b = new String(a);
Run Code Online (Sandbox Code Playgroud)
现在,如果您只是创建对新创建的b
变量的引用会发生什么?
// 'c' now points to the same instance as 'b'
String c = b;
Run Code Online (Sandbox Code Playgroud)
想象一下,您将c
(或更具体地说,它正在引用的对象)传递给另一个线程上的方法,并继续使用主线程上的相同实例.现在想象如果字符串是可变的会发生什么.
无论如何,这是为什么?
没有别的,这是因为不可变对象使多线程更简单,通常更快.如果在不同线程之间共享可变对象(可能是任何有状态对象,具有可变的私有/公共字段或属性),则需要特别注意确保同步访问(互斥,信号量).即便如此,您需要特别注意确保所有操作的原子性.多线程很难.
关于性能影响,请注意,通常将整个字符串复制到新实例中以便更改单个字符,实际上比由于确保线程安全访问所需的同步构造而导致昂贵的上下文切换更快.正如您所提到的,不变性还提供了实习可能性,这意味着它实际上可以帮助减少内存使用.
一般来说,制作尽可能多的东西是一个不错的主意.
归档时间: |
|
查看次数: |
8921 次 |
最近记录: |