繁体   English   中英

声明一个字符串和将其声明为final之间有什么区别?

[英]What is the difference between declaring a String and declaring it as final?

我知道字符串是不可变的。

然后,两者之间有什么区别?

String name ="Name";
final String name ="Name";

为什么在这种情况下使用final 因为String已经是不可变的,所以似乎没有必要。 第二个相关问题,为什么String是immutable 其他数据类型(如int,boolean)则不是。 如果String是不可变的,这是否使其成为线程安全的? 我读到“如果String是可变的,则可能已将加载“ java.io.Writer”的请求更改为加载“ mil.vogoon.DiskErasingWriter”” means什么means

这里有很多问题,但是这里有一些注释可以回答大多数问题:

  • final表示变量只能分配一次。 它与可变性无关,可变性是对象的属性,而不是变量(只是句柄)
  • String是不可变的,因为您无法更改其内部状态(它具有用于保存private char[] charsprivate char[] chars )。 基元也是不可变的。 在它们的包装等效项中更好地看到IntegerLong等。
  • 是的,一个String是线程安全的,因为无论有多少线程使用它,都无法更改其状态。 对字符串的每个操作都会导致一个新实例,而不是更改现有实例。

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

我读到“如果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设置为不可变的类型(以及其他一或两个事物),可以阻止这种攻击机制。

就像威廉所说:

final表示您无法为变量分配新值。

此外,如果您像这样玩匿名内部类:

final String mystring = "Hello";
button.addClickHandler(new ClickHandler() {
    void click() {
        System.out.println(mystring);
    }
});

mystring对象必须是最终对象。

它是对象与其参考之间的区别。 final变量只能分配一次值。 无论变量是否指向不可变对象,这都是正确的。

请注意,“不可变”对象本身通常(但不一定)由final引用集组成。

其他要点已经在这里得到了回答,但是您仍在寻找对所找到报价的解释:

如果String是可变的,则加载“ java.io.Writer”的请求可能已更改为加载“ mil.vogoon.DiskErasingWriter”

作为参考,这似乎是从不同的SO答案中得出的,该答案有些简短,但省略了细节。

通常,如果您编写一个接受可变对象并存储它们的公共类,或者返回一个正在存储的可变对象,则调用代码可以从该类的下面更改该对象。

举个例子。 免责声明:我对ClassLoader不太了解,所以这只是为了说明问题。 ClassLoader具有功能loadClass(String name) 想象一下,该方法首先检查该名称的类是否有效或受信任,然后加载它。 现在,如果String是可变的,则调用代码可以在检查了类之后,从类加载器的脚下更改类名称,从而规避安全措施。

当然,如果String是可变的,则可以希望ClassLoader的实现首先创建String的防御性副本 这样,调用代码没有任何机会规避安全性,因为它无法修改副本的内容。 这是一个通用规则:不要让调用代码对类的可变内部数据有任何处理。

所以字符串不需要是一成不变的,以确保安全类加载。 但是,对于不可变的对象,更容易确保这种安全性,因为它们根本无法在您身下更改。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM