考虑下面的例子。
String str = new String();
str = "Hello";
System.out.println(str); //Prints Hello
str = "Help!";
System.out.println(str); //Prints Help!
在Java中,String对象是不可变的。那么为什么对象str可以被赋值为"Help!"呢?这难道不是与Java中字符串的不变性相矛盾吗?有人能给我解释一下不变性的确切概念吗?
编辑:
好的。我现在明白了,但还有一个问题。下面的代码呢:
String str = "Mississippi";
System.out.println(str); // prints Mississippi
str = str.replace("i", "!");
System.out.println(str); // prints M!ss!ss!pp!
这是否意味着将再次创建两个对象(“Mississippi”和“M!ss!ss!pp!”),并且在replace()方法之后引用str指向不同的对象?
超级晚的答案,但想把一个简洁的消息从作者的String类在Java
字符串是常量;它们的值在被修改之后就不能再修改了
创建。字符串缓冲区支持可变字符串。因为字符串
对象是不可变的,它们可以被共享。
它可以从这个文档中导出,任何改变字符串的东西,都会返回不同的对象(可以是新的或旧的)。
关于这一点不那么微妙的提示应该来自函数签名。
想想看,为什么他们让一个对象上的函数返回一个对象而不是状态?
public String replace(char oldChar, char newChar)
还有一个来源使这种行为显式(从替换函数文档)
返回一个新字符串,该字符串由替换所有出现的
oldChar和newChar。
来源:https://docs.oracle.com/javase/7/docs/api/java/lang/String.html取代(char、% 20字符)
作者李·博因顿
作者阿瑟·范霍夫
作者马丁·布赫兹
作者乌尔夫·齐比斯
来源:JavaDoc of String。
我建议你读一读《Cup Size》——一个关于变量和值传递的故事(续《Cup Size》)。这对阅读上面的文章有很大帮助。
你读过吗?是的。好。
String str = new String();
这将创建一个名为“str”的新“远程控制”,并将其设置为值new String()(或“”)。
例如,在内存中创建:
str --- > ""
str = "Hello";
这将更改远程控制“str”,但不会修改原始字符串“”。
例如,在内存中创建:
str -+ ""
+-> "Hello"
str = "Help!";
这将更改远程控件“str”,但不会修改原始字符串“”或远程控件当前指向的对象。
例如,在内存中创建:
str -+ ""
| "Hello"
+-> "Help!"
Java中的String在Immutable和Final中只是意味着它不能被更改或修改:
案例1:
class TestClass{
public static void main(String args[]){
String str = "ABC";
str.concat("DEF");
System.out.println(str);
}
}
输出:美国广播公司(ABC)
原因:对象引用str没有改变,实际上是一个新对象
在池中创建了“DEF”,它根本没有引用
(也就是失去了)。
案例2:
class TestClass{
public static void main(String args[]){
String str="ABC";
str=str.concat("DEF");
System.out.println(str);
}
}
输出:六边形ABCDEF
原因:在这种情况下,str现在引用一个新对象“ABCDEF”
因此它打印ABCDEF,即前一个str对象“ABC”在池中丢失,没有引用。
public final class String_Test {
String name;
List<String> list=new ArrayList<String>();
public static void main(String[] args) {
String_Test obj=new String_Test();
obj.list.add("item");//List will point to a memory unit- i.e will have one Hashcode value #1234
List<String> list2=obj.list; //lis1 also will point to same #1234
obj.list.add("new item");//Hashcode of list is not altered- List is mutable, so reference remains same, only value in that memory location changes
String name2=obj.name="Myname"; // name2 and name will point to same instance of string -Hashcode #5678
obj.name = "second name";// String is Immutable- New String HAI is created and name will point to this new instance- bcoz of this Hashcode changes here #0089
System.out.println(obj.list.hashCode());
System.out.println(list2.hashCode());
System.out.println(list3.hashCode());
System.out.println("===========");
System.out.println(obj.name.hashCode());
System.out.println(name2.hashCode());
}
}
会产生这样的东西吗
1419358369
1419358369
103056
65078777
不可变对象的目的是它的值一旦被赋值就不应该被改变。
它将返回新对象,每次你试图改变它基于实现。
注意:可以使用Stringbuffer而不是string来避免这种情况。
对于你的最后一个问题::u将有一个引用,在字符串池中有2个字符串。
除了参考将指向m!ss!ss!pp!
str引用的对象可以更改,但实际的String对象本身不能更改。
包含字符串“Hello”和“Help!”的String对象不能改变它们的值,因此它们是不可变的。
String对象的不可变性并不意味着指向该对象的引用不能改变。
防止str引用更改的一种方法是将其声明为final:
final String STR = "Hello";
现在,尝试将另一个String赋值给STR将导致编译错误。