Lig*_*dle 211 java string immutability
请考虑以下示例.
String str = new String();
str = "Hello";
System.out.println(str); //Prints Hello
str = "Help!";
System.out.println(str); //Prints Help!
Run Code Online (Sandbox Code Playgroud)
现在,在Java中,String对象是不可变的.那么为什么对象str可以赋值"帮助!".这与Java中字符串的不变性相矛盾吗?任何人都可以向我解释一下不变性的确切概念吗?
编辑:
好.我现在得到它,但只是一个后续问题.以下代码如何:
String str = "Mississippi";
System.out.println(str); // prints Mississippi
str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!
Run Code Online (Sandbox Code Playgroud)
这是否意味着再次创建了两个对象("Mississippi"和"M!ss!ss!pp!"),并且引用str指向replace()方法之后的另一个对象?
gus*_*afc 298
str它不是一个对象,它是对象的引用."Hello"并且"Help!"是两个不同的String对象.因此,str 指向一个字符串.您可以更改它指向的内容,但不能更改它指向的内容.
拿这个代码,例如:
String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"
Run Code Online (Sandbox Code Playgroud)
现在,没有什么1,我们可以做些什么来s1会影响价值s2.它们引用相同的对象 - 字符串"Hello"- 但该对象是不可变的,因此无法更改.
如果我们这样做:
s1 = "Help!";
System.out.println(s2); // still prints "Hello"
Run Code Online (Sandbox Code Playgroud)
在这里,我们看到了变异对象和更改引用之间的区别.s2仍然指向我们最初设置s1指向的同一个对象.设置s1为"Help!"仅更改引用,而String它最初引用的对象保持不变.
如果字符串是可变的,我们可以这样做:
String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"
Run Code Online (Sandbox Code Playgroud)
编辑以响应OP的编辑:
如果你看一下String.replace(char,char)的源代码(也可以在你的JDK安装目录中的src.zip中找到 - 专业提示就是在你想知道某些东西是如何工作的时候看到那里)你可以看到它确实如下:
oldChar当前字符串中出现一个或多个匹配项,请复制当前字符串,其中所有匹配项oldChar都将替换为newChar.oldChar当前字符串中不存在,则返回当前字符串.所以,是的,"Mississippi".replace('i', '!')创建一个新String对象.以下是:
String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects
Run Code Online (Sandbox Code Playgroud)
您现在的功课就是看上面的代码做什么,如果你改变s1 = s1.replace('i', '!');来s1 = s1.replace('Q', '!');:)
1实际上,它是可能的突变的字符串(和其他不可变的对象).它需要反射并且非常非常危险,除非您真正对破坏程序感兴趣,否则永远不应该使用它.
coo*_*ird 23
str引用的对象可以更改,但实际String对象本身不能更改.
在String包含对象字符串"Hello"和"Help!"不能改变它们的值,因此,它们是不可变的.
String对象的不变性并不意味着指向对象的引用不能改变.
可以阻止str引用更改的一种方法是将其声明为final:
final String STR = "Hello";
Run Code Online (Sandbox Code Playgroud)
现在,尝试另一种分配String到STR会引起编译错误.
Mic*_*mlk 10
Light_handle我建议你读一下杯子大小 - 一个关于变量的故事和传递价值请(杯子大小继续).阅读上述帖子时,这将有很大帮助.
你读过它们吗?是.好.
String str = new String();
Run Code Online (Sandbox Code Playgroud)
这将创建一个名为" str" 的新"遥控器",并将其设置为值new String()(或"").
例如在内存中这会创建:
str --- > ""
Run Code Online (Sandbox Code Playgroud)
str = "Hello";
Run Code Online (Sandbox Code Playgroud)
然后,这会更改遥控器" str",但不会修改原始字符串"".
例如在内存中这会创建:
str -+ ""
+-> "Hello"
Run Code Online (Sandbox Code Playgroud)
str = "Help!";
Run Code Online (Sandbox Code Playgroud)
然后,这会更改遥控器" str",但不会修改原始字符串""或遥控器当前指向的对象.
例如在内存中这会创建:
str -+ ""
| "Hello"
+-> "Help!"
Run Code Online (Sandbox Code Playgroud)
让我们把它分成几个部分
String s1 = "hello";
Run Code Online (Sandbox Code Playgroud)
此Statement 在内存中创建包含hello和占用空间的字符串,即在Constant String Pool中,并将其分配给引用对象s1
String s2 = s1;
Run Code Online (Sandbox Code Playgroud)
此语句将相同的字符串hello分配给新引用s2
__________
| |
s1 ---->| hello |<----- s2
|__________|
Run Code Online (Sandbox Code Playgroud)
两个引用都指向相同的字符串,因此输出相同的值,如下所示.
out.println(s1); // o/p: hello
out.println(s2); // o/p: hello
Run Code Online (Sandbox Code Playgroud)
虽然String是不可变的,但是可以进行赋值,因此s1现在将引用新的值堆栈.
s1 = "stack";
__________
| |
s1 ---->| stack |
|__________|
Run Code Online (Sandbox Code Playgroud)
但是那个指向你好的s2对象会是什么样子呢.
__________
| |
s2 ---->| hello |
|__________|
out.println(s1); // o/p: stack
out.println(s2); // o/p: hello
Run Code Online (Sandbox Code Playgroud)
由于String是不可变的,因此Java虚拟机不允许我们通过其方法修改字符串s1.它将在池中创建所有新的String对象,如下所示.
s1.concat(" overflow");
___________________
| |
s1.concat ----> | stack overflow |
|___________________|
out.println(s1); // o/p: stack
out.println(s2); // o/p: hello
out.println(s1.concat); // o/p: stack overflow
Run Code Online (Sandbox Code Playgroud)
注意如果String是可变的,那么输出就是
out.println(s1); // o/p: stack overflow
Run Code Online (Sandbox Code Playgroud)
现在你可能会惊讶为什么String有像concat()这样的方法来修改.以下片段将清除您的困惑.
s1 = s1.concat(" overflow");
Run Code Online (Sandbox Code Playgroud)
这里我们将字符串的修改值赋给s1引用.
___________________
| |
s1 ---->| stack overflow |
|___________________|
out.println(s1); // o/p: stack overflow
out.println(s2); // o/p: hello
Run Code Online (Sandbox Code Playgroud)
这就是为什么Java决定将String作为最终类的原因,否则任何人都可以修改和更改string的值.希望这会有所帮助.
关于问题的替换部分,请尝试以下方法:
String str = "Mississippi";
System.out.println(str); //Prints Mississippi
String other = str.replace("i", "!");
System.out.println(str); //still prints Mississippi
System.out.println(other); // prints M!ss!ss!pp!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
87958 次 |
| 最近记录: |