“新的String()”是不可变的吗?
我一直在研究Java String。 以下问题是基于下面的post
Javastring是特殊的
java中string的不变性
-
不变性:现在,通过不变性来deviseString类,以便公共池中的值可以在其他地方/variables中重用。 如果
String
创build为String a = "Hello World!";
不过,如果我创buildString就好String b = new String("Hello World!");
为什么这个不变呢? (或者是?)。 由于这有一个专用的堆内存,我应该能够修改这个不影响任何其他variables。 那么在devise上,为什么String
作为一个整体被认为是不可变的? 或者我的上述假设是错误的? -
我想问的第二件事是关于常见的string池 。 如果我创build一个string对象
String c = "";
是在池中创build的空条目?
有没有任何职位已经在这些? 如果是这样,有人可以分享链接?
new String()
是一个产生String
的expression式…而且一个String
是不可变的,不pipe它是如何产生的。
(询问new String()
是否可变是无意义的,它是程序代码,而不是一个值,但我认为这不是你的意思。
如果我创build一个string对象作为
String c = "";
是在池中创build的空条目?
是; 即为空string创build一个条目。 没有什么特别的空String
。
(要迂腐,在你的代码被执行之前, ""
的池入口就会被创build,实际上,它是在你的代码被加载时创build的,或者甚至可能早于此。
所以,我想知道新的堆对象是否是不可变的,…
是的。 但是不变性是String对象的一个基本属性。 所有的String
对象。
你看, String
API根本不提供任何方法来改变一个String
。 所以(除了使用reflection的一些危险和愚蠢的技巧),你不能改变一个String
。
如果是这样的目的是什么?
Java String
被devise为一个不可变类的原因很简单。 如果核心string类提供了一个不可变的接口,它会使编写正确的程序变得更容易,并且读取/推理其他人的代码。 (或者至less,据我了解,这是devise决定的基本原理。)
按照答案,我收集到对同一variables的其他引用是原因之一。 请让我知道,如果我理解这一点是正确的。
不,这比这更重要。 简单地说,所有的String
对象都是不可变的。 理解这一点不需要复杂的特殊情况推理。 它只是“是”。
为了logging,如果你想在Java中使用一个可变的“string”对象,你可以使用StringBuilder
或者StringBuffer
。 但是这些是String的不同types。
1 – 这些技巧是(IMO)危险和愚蠢的原因是它们会影响可能由应用程序的其他部分通过string池共享的string的值。 这可能会导致混乱…在下一代维护您的代码的人几乎没有机会追查。
string是不可变的,不pipe它是如何实例化的
1)简短回答是 , new String()
也是不可变的。
因为您在String
上执行的每个可能的可变操作 (如replace
, toLowerCase
etcetra) 都不会影响原始 String
实例并返回一个新实例 。
您可以在Javadoc中检查String
。 所public
每个public
的String
方法都会返回一个新的String
实例,并且不会改变您调用该方法的当前实例。
这在multithreading环境中非常有用,因为每次传递或共享String
都不必考虑可变性( 某人将更改值 )。 String
可以很容易地成为最常用的数据types,所以devise人员祝福我们所有人不要每次都想到可变性,并为我们节省了很多痛苦。
不可变性允许string池或caching
这是因为不变性属性,内部string池是可能的,因为当在其他地方需要相同的string值时,则返回不可变引用。 如果String
是可变的,那么就不可能像这样共享String
来节省内存。
串不可变性不是因为汇集,而是不变性有更多的利益附加在它。
stringinterning或pooling是Flyweightdevise模式的一个例子
2)是的,它将像任何其他String
一样作为空白String
也像其他String
实例一样多。
参考文献:
- string的不变性好处
Java库围绕约束进行了很大的优化,任何String
对象都是不可变的,不pipe该对象是如何构造的。 即使你使用new
创build你的b
,你传递该实例的其他代码也会将这个值视为不可变的。 这是价值对象模式的一个例子,所有的优点(线程安全,不需要制作私人副本)都适用。
空string""
是一个合法的String
对象,就像其他任何东西一样,它恰好没有内部的内容,并且由于所有的编译时常量string都被实现了,所以我几乎可以保证一些运行时库已经使它成为添加到池中。
1)不变的部分不是因为游泳池; 它只是使游泳池成为可能。 string通常作为parameter passing给其他函数,甚至与其他线程共享; 使string不变是一个devise决定,使这种情况下的推理更容易。 所以是的 – 在Java中的String
总是不变的,不pipe你如何创build它们(请注意,在java中可能有可变string – 而不是String
类)。
2)是的。 大概。 我实际上不是100%肯定的,但应该是这样的。
这不是严格的回答你的问题,但如果你的问题背后是希望有可变的string,你可以操纵,你应该检查出的StringBuilder
类,它实现了许多完全相同的方法, String
有,但也增加方法来改变当前的内容。
一旦你build立了一个你满意的string,你只需要在它上面调用toString()
就可以把它转换成普通的String
,你可以传递给库函数和其他函数,秒。
另外, StringBuilder
和String
实现了CharSequence
接口,所以如果你想在自己的代码中编写可以同时使用可变和不可变string的函数,你可以声明它们接受任何CharSequence
对象。
从Java Oracle文档 :
string是不变的; 他们的价值创造后不能改变 。
然后再次:
string缓冲区支持可变string。 因为String对象是不可变的,所以它们可以共享。
一般而言,“所有原始的”(或相关的)对象都是不变的(请接受我的forms主义的缺乏)。
关于堆栈溢出的相关文章:
- Java中string的不变性
- Javastring是不可变的吗?
- Java是“通过引用传递”还是“按值传递”?
- 一个Javastring真的是不可变的?
- string是不可变的。 究竟是什么意思?
- 在java中使string不可变的原因是什么?
关于对象池 :对象池是一个java优化,与不可变的无关。
string是不可变的,意味着不pipe你如何创build它,你都不能改变对象本身。至于第二个问题:是的,它会创build一个条目。
实际上,这是相反的。
String
类的devise使得公共池中的值可以在其他地方/variables中重用。
不, 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);
现在,如果你简单地创build一个对新创build的b
variables的引用,会发生什么?
// 'c' now points to the same instance as 'b' String c = b;
想象一下,你将c
(或者更确切的说,它所引用的对象)传递给另一个线程上的一个方法,并继续在你的主线程中使用相同的实例。 现在想象一下,如果string是可变的,会发生什么。
为什么这是这种情况呢?
如果没有别的,那是因为不可变的对象使得multithreading更简单,而且通常更快。 如果你在不同的线程之间共享一个可变对象(这将是任何有状态的对象,具有可变的私有/公共字段或属性),你需要特别注意确保同步访问(互斥量,信号量)。 即使这样,你也需要特别的注意,以确保所有操作的primefaces性。 multithreading很难。
关于性能影响,请注意,为了更改单个字符,经常将整个string复制到新实例中,实际上比由于确保线程安全访问所需的同步构造而引发昂贵的上下文切换要快。 正如你所提到的,不变性也提供了实习的可能性,这意味着它实际上可以帮助减less内存使用。
尽可能多地创造不变的东西通常是个不错的主意。
1)不变性:如果出于安全原因使用新的或其他方式创buildstring,string将是不可变的
2)是的,在string池中将会有一个空的条目。
你可以更好地理解使用代码的概念
String s1 = new String("Test"); String s2 = new String("Test"); String s3 = "Test"; String s4 = "Test"; System.out.println(s1==s2);//false System.out.println(s1==s3);//false System.out.println(s2==s3);//false System.out.println(s4==s3);//true
希望这将有助于您的查询。 您可以随时查看String类的源代码,以便更好地理解链接: http : //grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String的.java
1- string是不可变的。看到这个:
一个Javastring真的是不可变的?
所以你可以用很多方式来创build它。
2 – 简答: 是的将是空的。
创build的string永远是不可变的,不pipe它们是如何创build的。
回答你的问题:
-
唯一的区别是:
当创buildstring像 –{String a = "Hello World!";}
那么只有一个对象被创build。
当它创build像 –{String b = new String("Hello World!");}
然后创build两个对象 。 第一个,因为你已经使用'新'关键字,第二个因为string属性。 -
是肯定的。 游泳池中将会创build一个空的条目。
string是不可变的,因为它不提供修改它的意思。 这是devise,以避免任何篡改(这是最后的,底层arrays不应该被触摸…)。
同样,Integer是不可变的,因为没有办法修改它。
不pipe你如何创build它。
不可变性不是new
function,它是String
类的一个特性。 它没有mutator方法,所以它是不可变的。
String A = "Test" String B = "Test"
现在stringB called
“Test”.toUpperCase() which change the same object into
“TEST” , so
A will also be
“TEST”,这是不可取的。
请注意,在您的示例中,引用已更改,而不是引用的对象,即b
作为引用可能会更改并引用新的对象。 但是这个新对象是不可变的,这意味着它的内容不会在调用构造函数之后被改变。
您可以使用b=b+"x";
更改stringb=b+"x";
或者b=new String(b);
,并且variablesa
的内容似乎会改变,但是不要混淆引用(这里是variablesb
)和它引用的对象的不可变性(在C中指向的指针)。 引用指向的对象在创build后将保持不变。
如果您需要通过更改对象的内容(而不是更改引用)来更改string,则可以使用StringBuffer
,它是String的可变版本。