在所有编程语言领域,我想字符串应该是地球上最常用的表达手段了吧。


在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不可变性的更多相关文章

  1. 浅析String

    浅析String String的设计结构: 首先我们看一下 String的源码 public final class String     implements java.io.Serializabl ...

  2. java基础解析系列(九)---String不可变性分析

    java基础解析系列(九)---String不可变性分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析系列(二)---In ...

  3. 记一次愚蠢的经历--String不可变性

    前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 记录一次在写代码时愚蠢的操作,本文涉及到的知识点:S ...

  4. 浅析String、StringBuilder、StringBuffer

    谈谈我对 String.StringBuilder.StringBuffer 的理解 StringBuilder.StringBuffer 和 String 一样,都是用于存储字符串的. 1.那既然有 ...

  5. 一、图解Java中String不可变性

    这里有一堆例子来说明Java的String的不可变性. 1.声明一个String String s = "abcd"; s 变量保存string对象的引用,下面的箭头解释成保存了哪 ...

  6. Java基础:String不可变性和final修饰

    转载请注明出处: jiq•钦's technical Blog - 季义钦 String的不可变性 Java规定String是不可变的(immutable).事实上这个不可变具备两层含义: 1 内容不 ...

  7. String不可变性

    今天分析一下String,String有很多实用的特性,比如说“不可变性”,是工程师精心设计的艺术品.用final就是拒绝继承,防止内部属性或方法被破坏. 一,什么是不可变? String不可变很简单 ...

  8. 浅析String、StringBuffer、StringBuilder的区别以及性能区别

    前奏: 比较三者之间的区别在与区别他们做相同的事情的时候的区别,那就是在我们常见的拼接字符串的时候,StringBuffer.StringBuilder调用的是appende()方法,而String很 ...

  9. 浅析String类

    这是对于String类的一些总结,我将会从几个方面并且结合着字符串池等相关知识进行总结 进程如下:                1.对于String类基本知识的一些总结 2.简要介绍字符串池 3.分 ...

随机推荐

  1. java 多线程 继承Thread和实现Runnable的区别

    1)继承Thread: public class ThreadTest extends Thread { private int count; private String name; public ...

  2. 完美解决 Linux 下 Sublime Text 中文输入

    首先,我参考了好几篇文章,都是蛮不错的,先列出来: sublime-text-imfix:首先推荐这个方法,最简单,但是在我的系统上有些问题.可用这个的强烈推荐用这个 完美解决 Linux 下 Sub ...

  3. .NET面试题系列[0] - 写在前面

    .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] - .NET框架基础知识(2) .NET面试题系列[3] - C# 基础知识(1) .NET ...

  4. 递归算法经典实例小结(C#实现)

     一 .递归算法简介 在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法. 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往 ...

  5. Html5 实现灯笼绘制

    最近在学习Html5,就用JavaScript在Canvas试着绘制了一个灯笼,并作了简要的说明. 具体绘制思路在页面上有说明,不再赘述,代码如下: <script type="tex ...

  6. Java 浅析三大特性之一继承

    上文Java 浅析三大特性之一封装我们说到Java是一个注重编写类,注重于代码和功能复用的语言.Java实现代码复用的方式有很多,这里介绍一个重要的复用方式--继承. 在介绍继承之前,我们要明确一点, ...

  7. window系统JDK1.7的快速配置

    快速配置java环境变量 右键单击计算机--->属性 点击 "高级系统设置"--->"环境变量",出现环境变量设置窗口 系统变量--->新建 ...

  8. 操作数据库mysql

    显示表结构 desc 表 显示数据库信息 show  create database 数据库名 show create table 表名

  9. javaScript 基础知识

    一.三个对话框 1.alert("提示信息") 弹出只带有一个确定按钮的对话框2.confirm("提示信息") 弹出有确定和取消按钮的对话框3.prompt( ...

  10. Eclipse 常用快捷键 (动画讲解)

    Eclipse有强大的编辑功能, 工欲善其事,必先利其器, 掌握Eclipse快捷键,可以大大提高工作效率.  编辑相关快捷键 注释          Ctrl + / 快速修复    Ctrl + ...