为什么 String 类在 Java 中被声明为 final?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2068804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the String class declared final in Java?
提问by Alex Ntousias
From when I learned that the class java.lang.String
is declared as final in Java, I was wondering why that is. I didn't find any answer back then, but this post: How to create a replica of String class in Java?reminded me of my query.
当我得知该类java.lang.String
在 Java 中被声明为 final 时,我想知道为什么会这样。当时我没有找到任何答案,但是这篇文章:如何在 Java 中创建 String 类的副本?让我想起了我的查询。
Sure, String provides all the functionality I ever needed, and I never thought of any operation that would require an extension of class String, but still you'll never know what someone might need!
当然,String 提供了我需要的所有功能,而且我从未想过任何需要扩展 String 类的操作,但您仍然永远不知道某人可能需要什么!
So, does anyone know what the intent of the designers was when they decided to make it final?
那么,有谁知道设计师在决定最终确定时的意图是什么?
采纳答案by Bruno Reis
It is very useful to have strings implemented as immutable objects. You should read about immutabilityto understand more about it.
将字符串实现为不可变对象非常有用。您应该阅读有关不变性的内容以了解更多信息。
One advantage of immutable objectsis that
不可变对象的优点之一是
You can share duplicates by pointing them to a single instance.
您可以通过将它们指向单个实例来共享重复项。
(from here).
(从这里)。
If String were not final, you could create a subclass and have two strings that look alike when "seen as Strings", but that are actually different.
如果 String 不是最终的,您可以创建一个子类并拥有两个在“视为字符串”时看起来相似但实际上不同的字符串。
回答by AaronLS
It may have been to simplify implementation. If you design a class that will be inheritable by users of the class, then you have a whole new set of use cases to consider into your design. What happens if they do this or that with X proptected field? Making it final they can focus on getting the public interface working correctly and make sure it's solid.
可能是为了简化实施。如果您设计的类可由该类的用户继承,那么您需要在设计中考虑一组全新的用例。如果他们对 X 保护字段这样做或那样做会发生什么?最终他们可以专注于让公共接口正常工作并确保它是可靠的。
回答by Thilo
String
is a very core class in Java, many things rely on it working a certain way, for example being immutable.
String
是 Java 中的一个非常核心的类,很多事情都依赖于它以某种方式工作,例如不可变。
Making the class final
prevents subclasses that could break these assumptions.
创建类final
可以防止可能破坏这些假设的子类。
Note that, even now, if you use reflection, you can break Strings(change their value or hashcode). Reflection can be stopped with a security manager. If String
was not final
, everyone could do it.
请注意,即使是现在,如果您使用反射,您也可以破坏字符串(更改它们的值或哈希码)。可以使用安全管理器停止反射。如果String
不是final
,每个人都可以做到。
Other classes that are not declared final
allow you to define somewhat broken subclasses (you could have a List
that adds to the wrong position, for example) but at least the JVM does not depend on those for its core operations.
其他未声明的类final
允许您定义一些损坏的子类(例如,您可能List
会在错误的位置添加一个),但至少 JVM 的核心操作不依赖于这些子类。
回答by Artur
As Bruno said it's about immutability. It's not only about Strings but as well about any wrappers e.g. Double, Integer, Character, etc. There are many reasons for this:
正如布鲁诺所说,这是关于不变性的。这不仅与字符串有关,还与任何包装器有关,例如 Double、Integer、Character 等。 造成这种情况的原因有很多:
- Thread safety
- Security
- Heap that is managed by Java itself (differently to ordinary heap that is Garbage Collected in different manner)
- Memory management
- 线程安全
- 安全
- 由 Java 本身管理的堆(不同于以不同方式收集垃圾的普通堆)
- 内存管理
Basically it so you, as a programmer, can be sure that your string will never be changed. It as well, if you know how it works, can improve memory managemnt. Try to create two identical string one after another, for example "hello". You will notice, if you debug, that they have identical IDs, that means that they are exactly THE SAME objects. This is due to the fact that Java let's you do it. This wouldn't be posssible if the strings were muttable. They can have the same I'd, etc., because they will never change. So if you ever decide to create 1,000,000 string "hello" what you'd really do is create 1,000,000 pointers to "hello". As well alling any function on string, or any wrappers for that reason, would result in creating another object (again look at object ID - it will change).
基本上是这样,作为程序员,您可以确保您的字符串永远不会被更改。如果您知道它是如何工作的,它也可以改进内存管理。尝试一个接一个地创建两个相同的字符串,例如“hello”。如果您进行调试,您会注意到它们具有相同的 ID,这意味着它们是完全相同的对象。这是因为 Java 让你来做这件事。如果字符串是可变的,这是不可能的。他们可以拥有相同的 Id 等等,因为他们永远不会改变。因此,如果您决定创建 1,000,000 个字符串“hello”,您真正要做的是创建 1,000,000 个指向“hello”的指针。以及所有字符串上的任何函数,或出于这个原因的任何包装器,都会导致创建另一个对象(再次查看对象 ID - 它会改变)。
Aditionally final in Java does not necessarilymean that object cannot change (it is different to for example C++). It means that the address to which it points cannot change, but you still can change it's properties and/or attributes. So understanding the difference between immutability and final in some case might be really important.
另外,Java 中的 final 并不一定意味着对象不能改变(它与例如 C++ 不同)。这意味着它指向的地址不能改变,但你仍然可以改变它的属性和/或属性。因此,在某些情况下理解不变性和 final 之间的区别可能非常重要。
HTH
HTH
References:
参考:
回答by Anurag
This is a nice articlethat outlines two reasons already mentioned on the above answers:
这是一篇不错的文章,概述了上述答案中已经提到的两个原因:
- Security: the system can hand out sensitive bits of read-only information without worrying that they will be altered
- Performance: immutable data is very useful in making things thread-safe.
- 安全性:系统可以分发只读信息的敏感位,而不必担心它们会被更改
- 性能:不可变数据在使事情线程安全方面非常有用。
And this probably is the most detailed comment in that article. Its has to do with the string pool in Java and security issues. Its about how to decide what goes into the string pool. Assuming both strings are equal if their sequence of characters are the same, then we have a race condition on who gets there first and along with it security issues. If not, then the string pool will contain redundant strings thus losing the advantage of having it in the first place. Just read it out for yourself, will ya?
这可能是那篇文章中最详细的评论。它与 Java 中的字符串池和安全问题有关。它是关于如何决定进入字符串池的内容。假设两个字符串相等,如果它们的字符序列相同,那么我们就有了一个关于谁先到达那里的竞争条件以及随之而来的安全问题。如果不是,那么字符串池将包含多余的字符串,从而失去首先拥有它的优势。自己读一读,好吗?
Extending String would play havoc with equals and intern. JavaDoc says equals:
扩展 String 会对 equals 和 intern 造成严重破坏。JavaDoc 说等于:
Compares this string to the specified object. The result is true if and only if the argument is not null and is a String object that represents the same sequence of characters as this object.
将此字符串与指定的对象进行比较。当且仅当参数不为 null 并且是表示与此对象相同的字符序列的 String 对象时,结果才为真。
Assuming java.lang.String
wasn't final, a SafeString
could equal a String
, and vice versa; because they'd represent the same sequence of characters.
假设java.lang.String
不是最终的, aSafeString
可以等于 a String
,反之亦然;因为它们代表相同的字符序列。
What would happen if you applied intern
to a SafeString
-- would the SafeString
go into the JVM's string pool? The ClassLoader
and all objects the SafeString
held references to would then get locked in place for the lifetime of the JVM. You'd get a race condition about who could be the first to intern a sequence of characters -- maybe your SafeString
would win, maybe a String
, or maybe a SafeString
loaded by a different classloader (thus a different class).
如果你申请intern
一个SafeString
--会发生什么- 会SafeString
进入 JVM 的字符串池吗?将ClassLoader
所有对象SafeString
保持引用然后将被锁定到位的JVM的生命周期。你会得到一个关于谁可能是第一个实习字符序列的竞争条件——也许你SafeString
会赢,也许 a String
,或者也许 aSafeString
由不同的类加载器(因此是不同的类)加载。
If you won the race into the pool, this would be a true singleton and people could access your whole environment (sandbox) through reflection and secretKey.intern().getClass().getClassLoader()
.
如果你赢得了进入游泳池的比赛,这将是一个真正的单身人士,人们可以通过反射和secretKey.intern().getClass().getClassLoader()
.
Or the JVM could block this hole by making sure that only concrete String objects (and no subclasses) were added to the pool.
或者 JVM 可以通过确保只有具体的 String 对象(并且没有子类)被添加到池中来阻止这个漏洞。
If equals was implemented such that SafeString
!= String
then SafeString.intern
!= String.intern
, and SafeString
would have to be added to the pool. The pool would then become a pool of <Class, String>
instead of <String>
and all you'd need to enter the pool would be a fresh classloader.
如果实现 equals 使得SafeString
!=String
则SafeString.intern
!= String.intern
,并且SafeString
必须添加到池中。该池然后将成为一个池,<Class, String>
而不是<String>
您需要进入池的所有内容将是一个新的类加载器。
回答by aioobe
In addition to the reasons mentioned in other answers (security, immutability, performance) it should be noted that String
has special language support. You can write String
literals and there's support for the +
operator. Allowing programmers to subclass String
, would encourage hacks such as:
除了其他答案中提到的原因(安全性、不变性、性能)之外,还应注意String
具有特殊的语言支持。您可以编写String
文字,并且支持+
运算符。允许程序员子类化String
,会鼓励黑客,例如:
class MyComplex extends String { ... }
MyComplex a = new MyComplex("5+3i");
MyComplex b = new MyComplex("7+4i");
MyComplex c = new MyComplex(a + b); // would work since a and b are strings,
// and a string + a string is a string.
回答by webdev
Well, I have some different thought I am not sure whether I am correct or not but in Java String is the only object which can be treated as a primitive data type as well I mean we can create a String object as String name="java". Now like others primitive datatypes which are copy by valuenot copy by referenceString is expected to have same behavior so thats why String is final. Thats what my thought it. Please ignore if its completely illogical.
好吧,我有一些不同的想法我不确定我是否正确但在 Java 中 String 是唯一可以被视为原始数据类型的对象我的意思是我们可以创建一个 String 对象作为String name="java ”。现在,像其他按值复制而不是按引用复制的原始数据类型一样,预计 String 具有相同的行为,这就是 String 是 final 的原因。这就是我的想法。如果完全不合逻辑,请忽略。
回答by Stephan Eggermont
To make sure we do not get a better implementation. It should of course have been an interface.
以确保我们不会得到更好的实施。它当然应该是一个接口。
[edit] Ah, getting more clueless down votes. The answer is perfectly serious. I've had to program my way around the stupid String implementation several times, leading to severe performance & productivity loss
[编辑] 啊,得到更多无能的反对票。答案是非常严肃的。我不得不多次围绕愚蠢的 String 实现进行编程,从而导致严重的性能和生产力损失
回答by Hymanob
The absolutely most important reason that String is immutable or final is that it is used by the class loading mechanism, and thus have profound and fundamental security aspects.
String 是不可变的或 final 的绝对最重要的原因是它被类加载机制使用,因此具有深刻和基本的安全方面。
Had String been mutable or not final, a request to load "java.io.Writer" could have been changed to load "mil.vogoon.DiskErasingWriter"
如果 String 是可变的或不是最终的,则加载“java.io.Writer”的请求可能已更改为加载“mil.vogoon.DiskErasingWriter”
reference : Why String is immutable in Java
回答by ncmathsadist
The finality of strings also defends them as a standard. In C++ you can create subclasses of string, so every programming shop could have its own version of string. This would lead to a lack of a strong standard.
字符串的终结性也使它们成为标准。在 C++ 中,您可以创建字符串的子类,因此每个编程商店都可以拥有自己的字符串版本。这将导致缺乏强有力的标准。