String被设计成不可变和不能被继承的原因

简介: String是所有语言中最常用的一个类。我们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。 主要是为了 “ 效率 ” 和 “ 安全性 ” 的缘故。 若 String 允许被继承, 由于它的高度被使用率, 可能会降低程序的性能,所以 String 被定义成 final。  

String是所有语言中最常用的一个类。我们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。

主要是为了 “ 效率 ”  “ 安全性 ” 的缘故。  String 允许被继承由于它的高度被使用率可能会降低程序的性能,所以 String 被定义成 final

 

一:String 和其他基本类型不同 , 他是个对象类型既然是对象类型 , 如果是在静态方法下是必须调用静态方法或值的 , 如果是非静态的方法 , 就必须要实例化.

 

main 函数是个 static 所以String 要能像其他的基本类型一样直接被调用这也是为什么在 main 函数下使用 String 类型不会报告错误的原因..

 

一下就解释了两个心里的疑问..

 

以前一直觉得奇怪 ,为什么 String 是对象类型在 main 函数下却是不需要实例化的再次佩服 java 设计人员想得真周到.

 

二:当定义 String 类型的静态字段(也成类字段),可以用静态变量(非 final)代替常量(final)加快程序速度。 反之,对于原始数据类型,例如 int,也成立。

 

例如,你可能创建一个如下的 String 对象:

 

Privatestatic final Stringx="example";

对于这个静态常量(由 final 关键字标识),你使用常量的每个时候都会创建一个临时的 String 对象。 在字节代码中,编译器去掉 ”x”,代替它的是字符串 “example”, 以致每次引用 ”x”  VM 都会进行一次哈希表查询。

 

相比之下,度于静态变量 (  final 关键字 ),字符串只创建一次。 仅当初始化 “x” 时, VM 才进行哈希表查询。

 

还有另一个解释 :

带有 final 修饰符的类是不可派生的。  java 核心 API 中,有许多应用 final 的例子,例如 java.lang.String  String 类指定 final 防止了人们覆盖 length() 方法。

 

另外,如果指定一个类为 final,则该类所有的方法都是 final java 编译器会寻找机会内联(inline)所有的 final 方法(这和具体的编译器实现有关)。 此举能够使性能平均提高 50%

 

示例:

 

publicclassTest{

publicstaticvoidmain(String[]args){

//

}

}

如果 String 不是 final 那么就可以继承

 

publicclassString2extendsString{

//..

//...

}

那我们的 main 也就可以写成

 

publicclassTest{

publicstaticvoidmain(String2[]args){//注意此处

//

}

}

英文参考:http://forums.sun.com/thread.jspa?threadID=636414

 

另外补充一点:

作用就是 final的类不能被继承,不能让别人继承有什么好处?

 

意义就在于,安全性,如此这般:

java 自出生那天起就是“为人民服务”,这也就是为什么java做不了病毒,也不一定非得是病毒,反正总之就是为了安全, 人家java的开发者目的就是不想让 java干这类危险的事儿,java并不是操作系统本地语言, 换句话说java必须借助操作系统本身的力量才能做事,JDK中提供的好多核心类比如 String,这类的类的内部好多方法的实现都不是java编程语言本身编写的, 好多方法都是调用的操作系统本地的API,这就是著名的“本地方法调用”,也只有这样才能做事,这种类是非常底层的, 和操作系统交流频繁的,那么如果这种类可以被继承的话,如果我们再把它的方法重写了,往操作系统内部写入一段具有恶意攻击性质的代码什么的, 这不就成了核心病毒了么?

 

上面所述是最重要的,另外一个方面,上面2位老兄说的也都很对, 就是不希望别人改,这个类就像一个工具一样,类的提供者给我们提供了, 就希望我们直接用就完了,不想让我们随便能改,其实说白了还是安全性, 如果随便能改了,那么java编写的程序肯定就很不稳定,你可以保证自己不乱改, 但是将来一个项目好多人来做,管不了别人,再说有时候万一疏忽了呢?他也不是估计的, 所以这个安全性是很重要的,javaC++相比,优点之一就包括这一点;

 

原因绝对不只有这么多,因为如果这些个核心的类都能被随便操作的话,那是很恐怖的,会出现好多好多未知的错误,莫名其妙的错误….

 

String类不可变性的好处

 

只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字符串。但如果字符串是可变的,那么String interning将不能实现(译者注:String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串。),因为这样的话,如果变量改变了它的值,那么其它指向这个值的变量的值也会一起改变。

 

如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连接,或者在socket编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞。

 

因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。

 

类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成不可知的破坏。

 

因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap中的键往往都使用字符串 

目录
相关文章
|
8月前
|
安全 Java 编译器
Java中的String实例化、Annotation注解类、继承的多态和Object类(附带相关面试题)
1.java中String两种实例化对象2.Annotation注解类 3.继承的多态 4.Object类
85 0
Java中的String实例化、Annotation注解类、继承的多态和Object类(附带相关面试题)
|
存储 Java 程序员
面试必问:String类型为什么设计成不可变的?
这几天在各大平台上都看到过这样一些帖子,全都是关于String类型对象不可变的问题,当然现在也是找工作的准备时期,因此花了一部分时间对其进行整理一下。 想要完全了解String,在这里我们需要解决以下几个问题 (1)什么是不可变对象? (2)String如何被设计成不可变对象的? (3)有什么办法能够改变String? (4)JAVA语言为什么把String类型设计成不可变? 带着这些问题就可以开始今天的文章了。
185 0
面试必问:String类型为什么设计成不可变的?
|
Java
你知道String类为什么不能被继承吗?
在找工作面试的时候我们经常会被问到一个问题,那就是String类能被继承吗?为什么?我们都知道String类不能被继承,但为什么不能却不能回答地很完整。
757 0
你知道String类为什么不能被继承吗?
|
存储 缓存 安全
【小家java】String类为什么要设计成final?不可变有什么优点?
【小家java】String类为什么要设计成final?不可变有什么优点?
【小家java】String类为什么要设计成final?不可变有什么优点?
|
Java
Java面试题 String类能不能被继承?为什么?
Java面试题 String类能不能被继承?为什么?
200 0
Java面试题 String类能不能被继承?为什么?
|
存储 Java
String不可变不可被继承源码分析
是否可变,String类能否被继承 重点,String是不可变的!String类不能被继承! String类是不可变的。
1018 0
|
缓存 安全 Java
为什么String要设计成不可变的?
翻译人员: 铁锚 翻译日期: 2013年11月18日 原文链接: Why string is immutable in Java ? 这是一个老生常谈的话题(This is an old yet still popular question). 在Java中将String设计成不可变的是综合考虑到各种因素的结果,想要理解这个问题,需要综合内存,同步,数据结构以及安全等方面的考虑. 在下文中,我将为各种原因做一个小结。
917 0
|
16天前
|
Java API 索引
Java基础—笔记—String篇
本文介绍了Java中的`String`类、包的管理和API文档的使用。包用于分类管理Java程序,同包下类无需导包,不同包需导入。使用API时,可按类名搜索、查看包、介绍、构造器和方法。方法命名能暗示其功能,注意参数和返回值。`String`创建有两种方式:双引号创建(常量池,共享)和构造器`new`(每次新建对象)。此外,列举了`String`的常用方法,如`length()`、`charAt()`、`equals()`、`substring()`等。
15 0