我正在查看 Sun 认证学习指南,其中有一段描述了最终修饰符。它说
“如果程序员可以自由地扩展我们所知道的 String 类文明,它可能会崩溃”
他什么意思 ?如果可以扩展 String Class ...我会不会有一个名为 MyString 的类继承所有 Strings 属性。仅通过扩展它怎么可能以任何方式更改实际的 String 类?
非常感谢您的回答
我正在查看 Sun 认证学习指南,其中有一段描述了最终修饰符。它说
“如果程序员可以自由地扩展我们所知道的 String 类文明,它可能会崩溃”
他什么意思 ?如果可以扩展 String Class ...我会不会有一个名为 MyString 的类继承所有 Strings 属性。仅通过扩展它怎么可能以任何方式更改实际的 String 类?
非常感谢您的回答
嗯,一个问题是,如果您可以继承 String 类,那么您很可能会以多种方式破坏 jvm 的安全性。许多权限检查各种字符串值以确定是否允许给定操作。如果您的代码提供字符串值,那么您可以返回一个 String 实例,当安全管理器查看它时该实例会“检出”,但稍后会像一个完全不同的值一样。
例如,假设您有一些敏感的 jvm 范围配置:
public static void registerProvider(String providerName, Provider impl) {
SecurityManager sm = ...;
if(sm != null) {
// say the check provider method doesn't allow strings starting with "com.sun."
sm.checkProvider(providerName);
}
_providerMap.put(providerName, impl);
}
现在,我实现了一个自定义 String ,如果传递了 value ,它会覆盖startsWith()
要返回的方法,但我的 String 的实际值确实以.false
"com.sun."
com.sun.
当然,更不用说字符串是不可变的一般期望,如果被破坏,可能会导致各种普遍的破坏(如其他答案中更详细地提到的那样)。
扩展类不会影响基类。但是,它可能会影响基类的消费者。
因此,假设您能够扩展String
,您可以编写如下内容:
class MyString extends String {
@Override
public int length() {
System.exit();
}
}
现在你将这个类传递给任何使用字符串的东西,你很可能会很快退出程序。不是文明的终结,而是你可以做一些更险恶的事情。
考虑到在整个 Java API 中,您将看到如下结构:
HashMap<String, Object> map;
它使用字符串进行索引。一个非常常见的事情,例如对于财产和 - 这在安全相关的地方可能是最糟糕的。此代码依赖于未经修改的代码String
来保持安全。
但是现在让您修改后的String
类允许例如就地反转字符串。
然后我们所知道的世界就会崩溃,因为到处都是地图会变得一团糟。日志记录会崩溃,等等。
很多代码依赖于String
类是不可变的,好吧,如果它真的是不可变的,那么你还想添加什么功能呢?
扩展一个类根本不会影响该类。然而,由于任何继承的类也是基类,它应该遵守基类的行为契约。如果程序员要更改常见的框架类型,那么您就不能指望这些类按预期工作。因此,您要防止滥用此类类的选项 - 这是使用final关键字完成的
String
实际上,问题与扩展或任何其他类无关。
问题实际上出在 Java 本身。问题是您实际上无法在其代码中定义特定对象实现的合同。它实际上并没有在代码中String
说明它是不可变的,因为不能指定不变性,它只能被编码。该合同仅产生于实际执行String
。
如果可以在 Java 语言中声明String
等是不可变的,那么我们就不需要创建这些类。在我看来,这是 Java 的一种令人衰弱的疾病,您无法在代码中定义合约。您只能对其进行编码和记录。Number
Integer
final
我希望能够扩展字符串并定义,也许,UppercaseString extends String
但contract(immutable,interned)
在 Java 中没有关键字,所以我不能这样做,因为为了最接近这个合同,唯一可用的关键字是final
而不是immutable
应该的。
灾难的夸张可能是对 String 的(不)可变性的安全方面的暗示。字符串通常作为参数传递给各种 I/O 资源连接 API(例如 JDBC 和文件 I/O)。这样的字符串通常是资源定位器和身份验证凭据的串联,并且该 API 将在返回连接之前执行检查以确保凭据对请求的资源有效。 如果 String 是可变的,它将为各种安全漏洞打开网关,因为资源指针/地址(例如数据库连接的数据库名称或包含用户敏感信息的文件名)可以在身份验证成功后修改但在为请求的原始资源建立资源连接之前,导致未经授权的访问和破坏访问控制。
使 String 不可变的另一个原因是使其成为线程安全的。