String为什么是不可变的?
前几天一个面试被问到String为什么是不可变的?
, 自我感觉当时回答的不太理想, 事后总结一下
不可变的是什么
我们谈论的String不可变, 指的是字符串的值不可变
例: String s = "hello"
s的值就是hello
, 不可变也指的是这个值不可变
类比到int基本类型就相当于int i = 1
, 假如这里i的值不可变, 那指的就是1不可变
为什么不可变
众所周知Java的String类型并非基本类型, 即String是一个类
既然String是类, 那我们就深入其内部实现来一探究竟
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
//......
}
从源码来看, String类内部是用char数组来保存字符串的值, 并且char[]是final的, 这里的final意味着什么呢?
- value必须在构造时为其赋值
- 赋值后value的引用不能再变
当我们实例化一个String对象并得到其引用后, 构造已经结束了, 即value的引用已经不能再变了
那么value的值呢, 理论上是可以改变的, 只要我们拿到value的引用, 可以直接通过下标改变他的值
实际上呢?
value的值我们从String外部获取不到
- 首先, 构造的时候我们传入String的值, String内部赋值给value字段的时候都经过copy, 也就是说我们传给String的值经过构造后已经有了一份我们获取不到的备份留在了String内部, 我们改变原来的值对String内部的value已经毫无影响
char[] c = new char[32];
c[0] = 'h';
String s = new String(c);
System.out.println(s);
c[1] = 'e';
System.out.println(s);
毫无疑问, 两次的输出都是h
其次, String类没有提供对外的接口来改变value的值, 通过查看String类源码可以看到, String类所有的公开方法中, 没有一个可以修改value的值
最后
String s = "hello";
s = "world";
这种情况, s的值貌似改变了, 从hello
变成了world
其实这里s所改变的是他所引用的对象, 并不是String对象的值改变了
怎么说呢? 我们这样String s = "hello"
写代码只是一种简写, 或者称为'语法糖'
实际执行的时候是什么样子的呢? 非要用Java代码表示的话大致意思是这样String s = String.valueOf("hello")
嗯? 这样表述貌似也有些问题... 改天再单独总结...
这里意思就是valueOf("hello")
会返回一个内部的value字段存的是"hello"的String对象
从上面几点分析我们知道, 拿到String对象的时候, 内部的value字段已经无法修改了
那么这里的s = "world"
, 这个赋值又是什么意思呢?
根据上面对valueOf
的分析, 这里的s = "world"
赋值之后s是一个内部字段存的是"world"的String对象
又因为value的值在String构造的时候就已经指定且不可再变, 所以这个s和之前的s引用的必然不是同一个对象
综上, 对s赋值是改变了s所引用的对象, 而改变前后两个String对象既不是同一个对象, 内部的value值又不一样
所以, 直接赋值也不能改变字符串的值, 改变的只是引用
所以, String不可变.
真的不可变吗?
按照上述的分析, 貌似真的不可变
因为一般情况下我们获取不到String内部的value数组的引用
那么二般情况呢
char[] origin = new char[32];
origin[0] = 'h';
String s = new String(origin);
System.out.println(s);
try {
Field f = s.getClass().getDeclaredField("value");
f.setAccessible(true);
Object o = f.get(s);
if(o instanceof char[]) {
char[] c = (char[]) o;
System.out.println(c.length);
c[1] = 'e';
c[2] = 'l';
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}
利用反射我们可以直接获取类内部的属性, 挣脱了访问权限的束缚
获取了String内部的value数组, 改变了String的值
假如以后遇到别的改变String值的方法, 再来记录
String为什么是不可变的?的更多相关文章
- Java中的String为什么是不可变的?
转载:http://blog.csdn.net/zhangjg_blog/article/details/18319521 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那 ...
- Java基础知识强化101:Java 中的 String对象真的不可变吗 ?
1. 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...
- 聊聊JAVA中 String类为什么不可变
前言 "我的风格比较偏传统和经典" 小明说,"我们在打扮自己的问题上还是蛮冒险的...我觉得当你是只狗的时候,穿什么都hold的住!" 哈哈哈,脱离单身狗快两年 ...
- 为什么Java中的String类是不可变的?
String类是Java中的一个不可变类(immutable class). 简单来说,不可变类就是实例在被创建之后不可修改. 在<Effective Java> Item 15 中提到了 ...
- 为什么String类是不可变的?
为什么String类是不可变的? String类 什么是不可变对象 当满足以下条件时,对象才是不可变的: 对象创建以后其状态就不能修改. 对象的所有域都是final类型的. 对象是正确创建的(在对象的 ...
- Java中的String为什么是不可变的? -- String源码分析
众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是, ...
- Java 中的 String 真的是不可变吗?
我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class String implements java.io.Seriali ...
- java中String类为什么不可变?
在面试中经常遇到这样的问题:1.什么是不可变对象.不可变对象有什么好处.在什么情景下使用它,或者更具体一点,java的String类为什么要设置成不可变类型? 1.不可变对象,顾名思义就是创建后的对象 ...
- String为什么是不可变的?
面试官Q1:请问为什么String是不可变的,能谈谈吗? 我们知道不管是面试初级.中级还是高级Java开发工程师,String永远都是一个绕不开的话题,而且问的问题也是各不相同,下面我们从几个角度来看 ...
随机推荐
- mysql5.6版本的优化
1. 目标 l 了解什么是优化 l 掌握优化查询的方法 l 掌握优化数据库结构的方法 l 掌握优化MySQL服务器的方法 2. 什么是优化? l 合理安排资源.调整系统参数使MySQL运行更快.更节省 ...
- 关于C++用法的学习心得
通过大一一学期对C++语言的学习,我感觉c++是一门有一定难度并且很有挑战性的科目,在c++学习过程中,我们懂得了其有很多的用法. 引用是C++引入的新语言特性,是C++常用的一个重要内容之一,正确. ...
- 我所理解的HTTP协议
前言 对于HTTP协议,想必大家都不陌生,在工作中经常用到,特别是针对移动端和前端开发人员来说,要获取服务端数据,基本走的网络请求都是基于HTTP协议,特别是RESTFUL + JSON 这种搭配特别 ...
- App设计:消息推送和界面路由跳转
概要 app消息推送.显示通知栏,点击跳转页面是很一般的功能了,下面以个推为例演示push集成,消息处理模块及app内部路由模块的简单设计. 推送 推送sdk集成 集成sdk步骤根据文档一步步做就行了 ...
- 动态调试|Maccms SQL 注入分析(附注入盲注脚本)
0x01 前言 已经有一周没发表文章了,一个朋友叫我研究maccms的代码审计,碰到这个注入的漏洞挺有趣的,就在此写一篇分析文. 0x02 环境 Web: phpstudySystem: Window ...
- post上传和压缩、插件模拟请求
gzip gzip一种压缩方式,或者是文件形式,它主要用于网络传输数据的压缩 gzip压缩好不好用 浏览器:网速一定.内容越小.请求响应的速度是不是更快 手机server:返回数据类型是json/ ...
- Kali学习笔记4:DNS信息收集
DNS记录 A记录 A记录是用来创建到IP地址的记录. A记录设置技巧 1.如果想创建不带www的记录,即cnblog.com,在主机记录中填写@或者留空,不同的注册商可能不一样. 2.创建多个域名到 ...
- Linux — 文件、目录管理
目录与路径 . 此层目录 .. 上层目录 - 之前一个工作目录 ~ 主文件夹 ~ account 指定用户的主文件夹,account --账号名称 cd 切换目录 pwd (print worki ...
- RestyCircuitBreaker --- openresty断路器
简介 由于某些场景下服务提供方和调用方都无法做到可用性,当系统远程调用时,可能会因为某些接口变慢导致调用方大量HTTP连接被阻塞而引发雪崩. 解决思路如下: 服务提供方实现接口快速失败,当处理时间达到 ...
- Python GUI之tkinter窗口视窗教程大集合(看这篇就够了)
一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 二.Tkinter 是什么 三.Tkinter 控件详细介绍 1. T ...