字符串是不可变的。 究竟是什么意思?
这个问题在这里已经有了答案:
在继续讨论不可变性的问题之前,我们先来看看String
类及其功能,然后再做出结论。
这是String
工作原理:
String str = "knowledge";
像往常一样,这将创建一个包含"knowledge"
的字符串,并为其分配一个引用str
。 够简单? 让我们执行一些更多的功能:
String s = str; // assigns a new reference to the same string "knowledge"
让我们看看下面的语句是如何工作的:
str = str.concat(" base");
这附加一个字符串" base"
的str
。 但是等等,这是如何实现的,因为String
对象是不可变的? 那么你的惊讶,它是。
当执行上述语句时,虚拟机将获取String str
的值,即"knowledge"
并附加" base"
,给我们值"knowledge base"
。 现在,由于String
是不可变的,VM不能将此值赋给str
,所以它创建一个新的String
对象,给它一个值"knowledge base"
,并给它一个引用str
。
这里需要注意的一点是,虽然String
对象是不可变的,但它的引用变量不是。 所以这就是为什么在上面的例子中引用了一个新形成的String
对象的原因。
在上面的例子中,我们有两个String
对象:第一个是我们用s
指向的值"knowledge"
创建s
,第二个是由str
指向的"knowledge base"
。 但是,从技术上讲,我们有三个String
对象,第三个是concat
语句中的文字"base"
。
关于字符串和内存使用的重要事实
如果我们没有什么其他的参考s
到"knowledge"
? 我们会丢失那个String
。 但是,它仍然会存在,但由于没有引用而被认为丢失。 下面再看一个例子
String s1 = "java";
s1.concat(" rules");
System.out.println("s1 refers to "+s1); // Yes, s1 still refers to "java"
发生了什么:
String
"java"
并将s1
引用它。 String
"java rules"
,但没有任何指向它。 所以,第二个String
会立即丢失。 我们无法达到它。 引用变量s1
仍然引用原始String
"java"
。
几乎每个应用于String
对象以修改它的方法都会创建新的String
对象。 那么,这些String
对象在哪里去? 那么,这些都存在于内存中,任何编程语言的关键目标之一就是高效地使用内存。
随着应用程序的增长, String
文字占据大量内存很常见,甚至会导致冗余。 因此,为了使Java更高效, JVM将一个特殊的内存区域称为“字符串常量池”。
当编译器看到一个String
文字时,它会查找池中的String
。 如果找到匹配项,那么对新文字的引用将直接指向现有的String
并且不会创建新的String
对象。 现有的String
只是多了一个参考。 这里有一点让String
对象不可变:
在String
常量池中,一个String
对象可能有一个或多个引用。 如果多个引用指向相同的String
而不知道它,如果其中一个引用修改了该String
值,那将会很糟糕。 这就是为什么String
对象是不可变的。
那么,现在你可以说,如果有人重写了String
类的功能呢? 这就是String
类被标记为final
的原因,所以没有人可以重写它的方法的行为。
字符串是不可变的,意味着你不能改变对象本身,但你可以改变对象的引用。 当你叫a = "ty"
,实际上改变的参考a
由字符串文字创造了一个新的对象"ty"
。 改变一个对象意味着使用它的方法来改变它的一个字段(或者这些字段是公开的而不是最终的,以便它们可以从外部更新而不用通过方法访问它们),例如:
Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"
虽然在一个不可变的类中(声明为final,以防止通过继承进行修改)(其方法不能修改其字段,并且这些字段始终是私有的并建议是最终的),例如String,但不能更改当前的String,但是您可以返回一个新的String,即:
String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"
你正在改变a
指向什么。 尝试这个:
String a="a";
System.out.println("a 1-->"+a);
String b=a;
a="ty";
System.out.println("a 2-->"+a);
System.out.println("b -->"+b);
你会看到a
和b
所指的对象没有改变。
如果你想防止更改代码,对象a
指,请尝试:
final String a="a";
链接地址: http://www.djcxy.com/p/20701.html
上一篇: String is immutable. What exactly is the meaning?
下一篇: Why can't I define a static method in a Java interface?