前几天一个面试被问到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为什么是不可变的?的更多相关文章

  1. Java中的String为什么是不可变的?

    转载:http://blog.csdn.net/zhangjg_blog/article/details/18319521 什么是不可变对象? 众所周知, 在Java中, String类是不可变的.那 ...

  2. Java基础知识强化101:Java 中的 String对象真的不可变吗 ?

    1. 什么是不可变对象?       众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对 ...

  3. 聊聊JAVA中 String类为什么不可变

    前言 "我的风格比较偏传统和经典" 小明说,"我们在打扮自己的问题上还是蛮冒险的...我觉得当你是只狗的时候,穿什么都hold的住!" 哈哈哈,脱离单身狗快两年 ...

  4. 为什么Java中的String类是不可变的?

    String类是Java中的一个不可变类(immutable class). 简单来说,不可变类就是实例在被创建之后不可修改. 在<Effective Java> Item 15 中提到了 ...

  5. 为什么String类是不可变的?

    为什么String类是不可变的? String类 什么是不可变对象 当满足以下条件时,对象才是不可变的: 对象创建以后其状态就不能修改. 对象的所有域都是final类型的. 对象是正确创建的(在对象的 ...

  6. Java中的String为什么是不可变的? -- String源码分析

    众所周知, 在Java中, String类是不可变的.那么到底什么是不可变的对象呢? 可以这样认为:如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的.不能改变状态的意思是, ...

  7. Java 中的 String 真的是不可变吗?

    我们都知道 Java 中的 String 类的设计是不可变的,来看下 String 类的源码. public final class String implements java.io.Seriali ...

  8. java中String类为什么不可变?

    在面试中经常遇到这样的问题:1.什么是不可变对象.不可变对象有什么好处.在什么情景下使用它,或者更具体一点,java的String类为什么要设置成不可变类型? 1.不可变对象,顾名思义就是创建后的对象 ...

  9. String为什么是不可变的?

    面试官Q1:请问为什么String是不可变的,能谈谈吗? 我们知道不管是面试初级.中级还是高级Java开发工程师,String永远都是一个绕不开的话题,而且问的问题也是各不相同,下面我们从几个角度来看 ...

随机推荐

  1. HashMap内部结构及实现原理

    简单介绍 在研究HashMap之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能 数组:采用一段连续的存储单元来存储数据.对于指定下标的查找,时间复杂度为O(1):通过给定值进行查找,需 ...

  2. 微软SSAS 错误 Internal error: Invalid enumeration value. Please call customer support! 不是此元素的有效值。

    错误 118 Internal error: Invalid enumeration value. Please call customer support! 不是此元素的有效值. 错误 119 分析 ...

  3. 笔记:安卓App消息处理机制

    内容简述 类似Binder机制,MessageQueue.Looper也有底层的C++实现,涉及文件管道和驱动等. 以下仅从Java层的Looper.Handler和MessageQueue等相关类型 ...

  4. 干货---stm32f103之DMA双缓冲__也算我为网络贡献的微薄之力

    思考再三:终究是要拿出一些干货--单片机基础核心代码,串口的高效率使用请这里开始.--举一反三,我只列出串口一的双dma缓冲应用范例,剩下的自己扩展.并给与了我迄今觉得最好的串口配置架构-感谢野火的高 ...

  5. DVWA 1.9 通关秘籍

    DVWA 1.9 通关秘籍   本文来源:i春秋社区-分享你的技术,为安全加点温度    DVWA (Dam Vulnerable Web Application) DVWA是用PHP+Mysql编写 ...

  6. js高级笔记

    定时器this指向window javascript 的执行过程 预解析(变量) 数据集和功能集---- 对象 对象----属性和方法 -------------------面向对象--------- ...

  7. 第81节:Java中的数组

    第81节:Java中的数组 本节介绍数组的基本概念,数据就是一种数据结构,可以用来存储多个数据,每个数组中可以存放相同类型的数据.比如,在学校,我们是一个班,这里的班级中每个同学都是这个班级数组中的元 ...

  8. Oracle的nvl函数和nvl2函数

    一.基本语法 介绍一下oracle的nvl函数和nvl2函数. nvl函数 nvl函数基本语法为nvl(E1,E2),意思是E1为null就返回E2,不为null就返回E1. nvl2函数 nvl2函 ...

  9. python pip 安装库文件报错:pip install ImportError: No module named _internal

    解决方法: pip2.7, you can at first curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py then python2. ...

  10. maven的标准pom.xml详解

    maven是构建和管理理项目的利器,pom.xml 是其核心.一个标准的pom.xml该怎么写?其中的标签又有什么意义?话不多说,请看代码: <?xml version="1.0&qu ...