我知道字符串是不可变的。
然后,有什么区别:
String name ="Name";
final String name ="Name";
为什么我们在这种情况下使用final
?因为String已经是不可变的,所以似乎没有必要。第二个相关问题,为什么String immutable
?其他数据类型如int,boolean则不是。如果String是不可变的,那么它是否具有线程安全性?我读到“如果String是可变的,加载”java.io.Writer“的请求可能已被更改为加载”mil.vogoon.DiskErasingWriter“” means
?
答案 0 :(得分:4)
这里有很多问题,但这里有一些注释应该回答大部分问题:
final
表示该变量只能分配一次。它与可变性无关,可变性是对象的属性,而不是变量(只是一个句柄)String
是不可变的,因为您无法更改其内部状态(它具有保存字符的private char[] chars
)。基元也是不可改变的。这在包装器等效物中更明显 - Integer
,Long
等。答案 1 :(得分:2)
final
表示您无法为变量分配新值。
String name = "Name";
name = "MyName"; // legal
final String name = "Name";
name = "MyName"; // illegal, compiler error
这是一篇关于为什么字符串是不可变的文章:
http://javarevisited.blogspot.com/2010/10/why-string-is-immutable-in-java.html
答案 2 :(得分:2)
我读到“如果String是可变的,加载”java.io.Writer“的请求可能已被更改为加载”mil.vogoon.DiskErasingWriter“”
行。首先要认识到的是,这是一个假设的讨论。字符串不可变。
现在想象一下这段代码:
public static final String CLASS_NAME = "java.io.Writer";
...
Class<?> clazz = Class.forName(CLASS);
这实际上加载了什么类?
如果String是可变的,那么在安全沙箱中运行的一些恶意代码将能够改变CLASS_NAME引用的String对象的内容。特别是,它可以将其从“java.io.Writer”更改为“mil.vogoon.DiskErasingWriter”。最终结果是你的应用程序会被欺骗加载错误的类。
通过使String成为不可变类型(以及其他一两件事),这种攻击机制就会被挫败。
答案 3 :(得分:1)
final意味着您无法为变量分配新值。
此外,如果您使用匿名内部类:
final String mystring = "Hello";
button.addClickHandler(new ClickHandler() {
void click() {
System.out.println(mystring);
}
});
mystring
对象必须为最终版。
答案 4 :(得分:1)
它是对象与其引用之间的区别。只能为final
变量赋值一次。无论变量是否指向不可变对象,都是如此。
请注意,“不可变”对象本身通常(但不一定)由final
个引用组成。
答案 5 :(得分:0)
其他要点已在这里得到解答,但您仍在寻找对您发现的引用的解释:
如果String是可变的,则加载“java.io.Writer”的请求可能有 已更改为加载“mil.vogoon.DiskErasingWriter”
作为参考,这似乎来自一个不同的SO答案,这个答案有点短,并且没有详细说明。
通常,如果你编写一个接受可变对象并存储它们的公共类,或者返回它存储的可变对象,那么调用代码可以从该类的脚下改变该对象。
举个例子。免责声明:我对ClassLoader了解不多,所以这只是为了说明问题。 ClassLoader有一个函数loadClass(String name)
。想象一下,该方法首先检查该名称的类是有效还是可信,然后加载它。现在,如果String是可变的,调用代码可以在已经检查过类之后从类加载器的脚下更改类名,从而规避安全措施。
当然,如果String是可变的,那么可以希望ClassLoader的实现首先会生成String的防御性副本。这样,调用代码就没有机会绕过安全性,因为它无法修改 copy 的内容。这是一般规则:不要让调用代码对类的可变内部数据有任何处理。
所以String not 需要是不可变的,以确保安全的类加载。但是,对于不可变对象,更容易确保这种安全性,因为它们根本无法从您下面进行更改。