java中String类为什么不可变?
在面试中经常遇到这样的问题:1、什么是不可变对象。不可变对象有什么好处。在什么情景下使用它,或者更具体一点,java的String类为什么要设置成不可变类型?
1、不可变对象,顾名思义就是创建后的对象不可以改变,典型的例子有java中的String类型。
2、相比于可变对象,不可变对象有很多优势:
(1)不可变对象可以提高String Pool(字符串常量池)的效率和安全性。如果你知道一个对象是不可变动 ,那么需要拷贝的对象的内容时就不用复制它本身二只是复制它的地址,复制地址(通常一个指针的大小)需要很小的内存,效率也很好。二对于其他引用同一个对象的其他变量也不会造成影响。
(2)可不变对象对于多线程滴安全的,因为在多线程同事进行的情况下,一个可变对象的值很可能被其他线程改变这样会造成不可预期的结果么人使用不可变对象就可以避免这种情况出现。
java将String设成不可变最大的原因是效率和安全。
那么不可变类型到底是怎么实现的呢?
在java中考虑到各种因素,需要综合到内存,数据结构以及安全的方面的考虑,在下文中,我会为各种原因做一个总结。
1、字符串常量池的需要
字符串常量池是java堆内存中一个特殊的存储区域,当创建一个String对象,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。
代码如下:
String s1 = "ABC";
String s2 = "ABC";
在java中内存分为堆内存和栈内存,堆内存存放的是对象,栈内存存储对象的引用,字符串“ABC”存放在堆内存中,而s1,s2作为对象的引用则存放在栈内存中,原理如下:
堆内存 栈内存
String对象 "ABC"______ s1 String变量的引用
|______ s2
假设:字符串对象允许改变,那么将会导致各种逻辑错误。比如改变一个对象却影响到另外一个独立的对象。
思考一下:一下代码,s1和s2还会指向同一个对象吗?
String s1 = "AB"+"C";
String s2 = "A"+"BC";
也许很多新手都会觉得不是指向同一个对象,但是考虑到现代编译器会进行常规的优化所以他们都会指向常量池中的同一个对象。
2、运行String对象缓存HashCode
java中String对象的哈希码被频繁的使用,比如在HashMap的容器中。
字符串不变性保证了hash码的唯一性,因此可以放心的进行缓存,这也是一种性能优化手段,意味着不必每次都取计算新的哈希码,在String类的定义中有如下代码:
private int hash;//用来缓存HashCode
3、安全性
String被许多的Java类(库)用来当做参数,例如 网络连接地址URL,文件路径path,
还有反射机制所需要的String参数等, 假若String不是固定不变的,将会引起各种安全隐患。
总体来说, String不可变的原因包括 设计考虑,效率优化问题,以及安全性这三大方面.
事实上,这也是Java面试中的许多 "为什么" 的答案。
4、String类不可变的好处
String是所有语言中最常用的一个类。我们知道在Java中,String是不可变的、final的。Java在运行时也保存了一个字符串池(String pool),这使得String成为了一个特别的类。
String类不可变性的好处
1.只有当字符串是不可变的,字符串池才有可能实现。字符串池的实现可以在运行时节约很多heap空间,因为不同的字符串变量都指向池中的同一个字 符串。但如果字符串是可变的,
那么String interning将不能实现(译者注:String interning是指对不同的字符串仅仅只保存一个,即不会保存多个相同的字符串。),因为这样的话,如果变量改变了它的值,那么
其它指向这个值的变量 的值也会一起改变。
2.如果字符串是可变的,那么会引起很严重的安全问题。譬如,数据库的用户名、密码都是以字符串的形式传入来获得数据库的连
接,或者在socket编程中,主机名和端口都是以字
符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符
串指向的对象的值,造成安全漏洞。
3.因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
4.类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载java.sql.Connection类,而这个值被改成了myhacked.Connection,那么会对你的数据库造成
不可知的破坏。
5.因为字符串是不可变的,所以在它创建的时候hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为Map中的键,字符串的处理速度要快过其它的键对象。这就是HashMap
中的键往往都使用字符串。
二、既然知道String类型不可变的好处和作用那么大,那么是否就不需要可变类型了呢?
当然不是,当你需要向字符串插入或修改的时候,Sting不可变类型就显得足襟见肘,这时候就需要一个可变的字符串类型:StringBuffer。
StringBuffer与String一样,都代表字符串,但是由于StringBuffer内部实现的方式和String不同,所以StringBuffer在处理字符串的时候
不产生新的对象,在内存使用上要由于String类。
java中String类为什么不可变?的更多相关文章
- 聊聊JAVA中 String类为什么不可变
前言 "我的风格比较偏传统和经典" 小明说,"我们在打扮自己的问题上还是蛮冒险的...我觉得当你是只狗的时候,穿什么都hold的住!" 哈哈哈,脱离单身狗快两年 ...
- 在java中String类为什么要设计成final?
大神链接:在java中String类为什么要设计成final? - 程序员 - 知乎 我进行了重新排版,并且更换了其中的一个例子,让我们更好理解. String很多实用的特性,比如说“不可变性”,是工 ...
- Java中String类为什么被设计为final?
Java中String类为什么被设计为final 首先,String是引用类型,也就是每个字符串都是一个String实例.通过源码可以看到String底层维护了一个byte数组:private f ...
- Java中String类的方法及说明
String : 字符串类型 一. String sc_sub = new String(c,3,2); // String sb_copy = new String(sb) ...
- java中String类学习
java中String类的相关操作如下: (1)初始化:例如,String s = “abc”; (2)length:返回字符串的长度. (3)charAT:字符操作,按照索引值获得字符串中的指定字符 ...
- 在java中String类为什么要设计成final
在java中String类为什么要设计成final? - 胖胖的回答 - 知乎 https://www.zhihu.com/question/31345592/answer/114126087
- 【转载】Java中String类的方法及说明
转载自:http://www.cnblogs.com/YSO1983/archive/2009/12/07/1618564.html String : 字符串类型 一. String sc_ ...
- 在Java中String类为什么要设计成final?String真的不可变吗?其他基本类型的包装类也是不可变的吗?
最近突然被问到String为什么被设计为不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下. 1.String的不可变String类被final修饰,是不可继承和 ...
- Java中String为什么是不可变的
1.在Java中,String类是不可变类,一个不可变类是一个简单的类,并且这个的实例也不能被修改, 这个类的实例创建的时候初始化所有的信息,并且这些信息不能够被修改 2.字符串常量池 字符串常量池是 ...
随机推荐
- linu输出重定向
1.tee命令 ls | tee filename #若出现Permission Denied使用下面 ls | sudo tee filename #清空filename后重写 ls | sudo ...
- # 2019-2020-4 《Java 程序设计》结对项目总结
2019-2020-4 <Java 程序设计>结对项目阶段总结---<四则运算--整数> 一.需求分析 实现一个命令行程序 要求: 自动生成小学四则运算题目(加,减,乘,除): ...
- h5页面关于复制某段文字
上次的项目有一段内容是点击复制按钮 然后复制一段文字,此段方法我才用的是range.selectNodeContents方法,range对象的SelectNodeContents方法将于range对象 ...
- Java WebService 简单实例使用JDK
原文地址:http://www.cnblogs.com/jasoncc/archive/2011/12/22/2296052.html 什么是WebServices? 它是一种构建应用程序的普 ...
- servlet概述(作业11)
1.什么是servlet. Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能 ...
- Redis Sentinel 配置文件
基础参考:https://www.cnblogs.com/wang-li/p/9955303.html 配置文件讲解 1.sentinel monitor # sentinel monitor < ...
- 通过iptables添加QoS标记
1.什么是QoS QoS是一种控制机制,它提供了针对不同用户或者不同数据流采用相应不同的优先级,或者是根据应用程序的要求,保证数据流的性能达到一定的水准.QoS的保证对于容量有限的网络来说是十分重要的 ...
- flask-cookie & session
Cookie @app.route('/') def hello_world(): name=request.cookies.get('Name') # 获取cookie resp = Respon ...
- springboot的拦截器Interceptor的性质
Interceptor在springboot2.x版本的快速入门 实现HandlerInterceptor的接口,并重载它的三个方法:preHandle.postHandle.afterComplet ...
- js实现图片查看器(图片的缩放、旋转、拖拽)
一.关于图片查看器. 目前网络上能找到的图片查看器很多,谁便一搜就能出来.如:jquery.iviewer.js.Viewer.js这两个js文件,其中功能也足够满足大部分开发需求.但是单纯的就想实现 ...