浅析String不可变性
在所有编程语言领域,我想字符串应该是地球上最常用的表达手段了吧。
在java的世界里,String是作为类出现的,核心的一个域就是一个char数组,内部就是通过维护一个不可变的char数组,来向外部输出的。

这是jdk一段String类定义,首先类是final,表明类不可被继承;核心域是private final的,final表明这个引用所指向的内存地址不会改变,但这还不足说明value[]是不可变的;因为引用所指向的内存的值有可能发生变化,但是jdk是不会让这样的事情发生的。private 保证这个域对外部来说是不可见的,这还不够,对value还要进行 保护性拷贝 。
举一个简单的例子:

这是一个String的构造函数,参数是一个char数组引用,它并没有把这个数组引用直接赋值给实例对象的value成员变量,而是通过一个Arrays.copyOf的方式拷贝一个数组再给到对象的成员变量。为什么呢?假设它这里是直接一个赋值,那String的不可变性就彻底被破坏了,因为如此一来,存在一个外部引用与实例对象value引用指向相同的内存地址,通过外部引用就可以改变这个char数组对象,最终导致的结果就是String不再不可变。幸好JDK中所有的对value的操作都是保护性拷贝操作,不管是被赋值,还是赋值给其它外部引用。
说了这么多,为什么JAVA要String保持一个不可变的状态呢?原因其实很简单,因为String太太太太常用了,地球上没有能比这个更常用的对象了,设计成不可变的,是为了减少大量的同步锁的开销。但是要注意 并不是声明成final的类一定是不可变的 。
根据effective java一书中提到,类不变需遵循五条规则:
1.不提供任何机会修改对象状态的方法
2.保证类不被扩展
3.所有域都是final
4.所有域都是私有的
5.确保对于任何可变组件的互斥访问
有兴趣的同学可以参考 effective 第十五条,这里就不展开讲了。作了那么久的铺垫,接下来可以谈谈avoid getfield opcode了,按翻译来说就是防止"调用访问域的操作码",这段tip来自一段注释。

十分常用的replace方法,内部算法大概是这样一个过程:先找到第一个oldChar的下标i,拷贝小标i之前的旧数组的内容到新的数组,新数组[i]='newChar',遍历i之后的内容,若旧数组出现为oldChar则在新数组中替换为newChar,若没有出现,则拷贝旧值到新数组。
起初我很奇怪,到底为什么,一定要找到第一个出现oldChar的下标,为什么不直接遍历数组中每一个char 若为旧值,替换为新值。我从时间复杂度,空间复杂度去考虑这个算法,始终没有得到结果。我还是太年轻啊,后来才发觉其实还是为了维护一个String的设计原则:"对于拥有相同的字符字面量的情况下,String的构造还是优先返回原字符串对象"。这么做应该是为了解决堆内存吧。
那么
,这一句注释到底是什么意思呢?要理解这句话,需要对JVM有一定的了解。
JVM在运行中的数据区,分为五个部分:方法区,堆区,虚拟机栈,本地方法栈,程序计数器。

首先类相关的信息肯定是放在方法区的,堆中放一些实例对象,程序计数器始终指向下一条将要执行的指令,虚拟机栈和本地方法栈分别是用来于普通方法和本地方法的。
着重说一下虚拟机栈,它是线程私有的,描述的是java方法执行的内存模型:每个方法在执行的同时创建一个栈帧,用于存放局部变量表,操作数栈,方法入口,动态链接等。
局部变量表用来存放一些基本数据类,和引用。操作数栈的话,是用来作运算用的,打个比方
int a=1;
int b =2;
int c =a+b;
JVM会先把a,b的值压入到操作数栈保存起来,等到程序计数器执行加法指令的时候,再把a,b从栈中pop出来。重点就在于a,b值是从哪里压入到栈中的,如果没有
那么接下来要遍历的就是value数组了,value毫无疑问是堆中的数据,也就是每一次遍历会经历,数据由堆中取出,进入栈帧,再由栈帧压入到操作数栈,最后pop出来进行运算。
如果执行了上述代码,情况就大不相同了,val就是一个局部变量,它会被存放在局部变量表中,接来下的运算,就是局部变量表到操作数栈了,属于一个栈帧内的数据转移。JVM为了避免频繁进行堆栈数据转移,将值复制到本地变量一次,以避免在接下来的几行中循环的每一次迭代,从堆中多次取下的字段值。
除了我提到的这些,String源码中还有许多值得学习的算法,设计方式,代码优化,比如
,还有常量池的实现。
最后我想求教一个问题啊,在JDK7点版本中,String引入了一段静态代码块,

我甚是不解啊,不知道有没有大神帮我解读一下这段代码的含义?
浅析String不可变性的更多相关文章
- 浅析String
浅析String String的设计结构: 首先我们看一下 String的源码 public final class String implements java.io.Serializabl ...
- java基础解析系列(九)---String不可变性分析
java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...
- 记一次愚蠢的经历--String不可变性
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 记录一次在写代码时愚蠢的操作,本文涉及到的知识点:S ...
- 浅析String、StringBuilder、StringBuffer
谈谈我对 String.StringBuilder.StringBuffer 的理解 StringBuilder.StringBuffer 和 String 一样,都是用于存储字符串的. 1.那既然有 ...
- 一、图解Java中String不可变性
这里有一堆例子来说明Java的String的不可变性. 1.声明一个String String s = "abcd"; s 变量保存string对象的引用,下面的箭头解释成保存了哪 ...
- Java基础:String不可变性和final修饰
转载请注明出处: jiq•钦's technical Blog - 季义钦 String的不可变性 Java规定String是不可变的(immutable).事实上这个不可变具备两层含义: 1 内容不 ...
- String不可变性
今天分析一下String,String有很多实用的特性,比如说“不可变性”,是工程师精心设计的艺术品.用final就是拒绝继承,防止内部属性或方法被破坏. 一,什么是不可变? String不可变很简单 ...
- 浅析String、StringBuffer、StringBuilder的区别以及性能区别
前奏: 比较三者之间的区别在与区别他们做相同的事情的时候的区别,那就是在我们常见的拼接字符串的时候,StringBuffer.StringBuilder调用的是appende()方法,而String很 ...
- 浅析String类
这是对于String类的一些总结,我将会从几个方面并且结合着字符串池等相关知识进行总结 进程如下: 1.对于String类基本知识的一些总结 2.简要介绍字符串池 3.分 ...
随机推荐
- java 多线程 继承Thread和实现Runnable的区别
1)继承Thread: public class ThreadTest extends Thread { private int count; private String name; public ...
- 完美解决 Linux 下 Sublime Text 中文输入
首先,我参考了好几篇文章,都是蛮不错的,先列出来: sublime-text-imfix:首先推荐这个方法,最简单,但是在我的系统上有些问题.可用这个的强烈推荐用这个 完美解决 Linux 下 Sub ...
- .NET面试题系列[0] - 写在前面
.NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] - .NET框架基础知识(2) .NET面试题系列[3] - C# 基础知识(1) .NET ...
- 递归算法经典实例小结(C#实现)
一 .递归算法简介 在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法. 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往 ...
- Html5 实现灯笼绘制
最近在学习Html5,就用JavaScript在Canvas试着绘制了一个灯笼,并作了简要的说明. 具体绘制思路在页面上有说明,不再赘述,代码如下: <script type="tex ...
- Java 浅析三大特性之一继承
上文Java 浅析三大特性之一封装我们说到Java是一个注重编写类,注重于代码和功能复用的语言.Java实现代码复用的方式有很多,这里介绍一个重要的复用方式--继承. 在介绍继承之前,我们要明确一点, ...
- window系统JDK1.7的快速配置
快速配置java环境变量 右键单击计算机--->属性 点击 "高级系统设置"--->"环境变量",出现环境变量设置窗口 系统变量--->新建 ...
- 操作数据库mysql
显示表结构 desc 表 显示数据库信息 show create database 数据库名 show create table 表名
- javaScript 基础知识
一.三个对话框 1.alert("提示信息") 弹出只带有一个确定按钮的对话框2.confirm("提示信息") 弹出有确定和取消按钮的对话框3.prompt( ...
- Eclipse 常用快捷键 (动画讲解)
Eclipse有强大的编辑功能, 工欲善其事,必先利其器, 掌握Eclipse快捷键,可以大大提高工作效率. 编辑相关快捷键 注释 Ctrl + / 快速修复 Ctrl + ...