最近突然被问到String为什么被设计为不可变,当时有点懵,这个问题一直像bug一样存在,竟然没有发现,没有思考到,在此总结一下。

1.String的不可变
String类被final修饰,是不可继承和修改的。当一个String变量被第二次赋值时,不是在原有内存地址上修改数据,而是在内存中重新开辟一块内存地址,并指向新地址。

String类为什么要被设计为是final的?

  1.不可变性支持线程安全。
  2.不可变性支持字符串常量池,提升性能。
  3.String字符串作为最常用数据类型之一,不可变防止了随意修改,保证了数据的安全性。

正常情况下Java的String字符串是final且不可变的。不过可以通过特殊手段修改它的内容。
String类的主力成员字段value是个char[ ]数组,而且是用final修饰的。final修饰的字段创建以后就不可改变。因为虽然value是不可变,也只是value这个引用地址不可变。挡不住Array数组是可变的事实。Array的数据结构看下图:

也就是说Array变量只是stack上的一个引用,数组的本体结构在heap堆。String类里的value用final修饰,只是说stack里的这个叫value的引用地址不可变。没有说堆里array本身数据不可变。

代码测试:

 String test = "immutable String";
String test1 = test;
String test2 = new String(test);
String test3 = new String(test.toCharArray());
Field values = String.class.getDeclaredField("value");
values.setAccessible(true);
char[] chars = (char[])values.get(test);
chars[] = 'u';
chars[] = 'n';
System.out.println("test==test1:" + (test == test1));
System.out.println("test==test2:" + (test == test2));
System.out.println("test1==test2:" + (test1 == test2));
System.out.println("test:" + test + " test1:" + test1 + " test2:" + test2 + " test3:" + test3);

由String的不可变性引申到其他基本数据类型: Byte,Short,Integer,Long,Double,Float,Character,Boolean 八种基本数据的包装类,仔细查看发现也是final修饰的,再仔细查看一下enum枚举类型,发现用javac编译后再用javap反编译也是被编译为final修饰的类,并且其枚举值全部定义为static final 修饰的成员变量。

由此发现,Java设计者在设计Java基本数据类型时,把基本数据类型全部设计为不可变的,这样既方便了开发人员,又保证了数据的安全性。

总结:Java中String是不可变的,但是可以通过反射修改其内容。

备注:
作者:Shengming Zeng
博客:http://www.cnblogs.com/zengming/

本文是原创,欢迎大家转载;但转载时必须注明文章来源,且在文章开头明显处给明链接。
<欢迎有不同想法或见解的同学一起探讨,共同进步>

在Java中String类为什么要设计成final?String真的不可变吗?其他基本类型的包装类也是不可变的吗?的更多相关文章

  1. 在java中String类为什么要设计成final

    在java中String类为什么要设计成final? - 胖胖的回答 - 知乎 https://www.zhihu.com/question/31345592/answer/114126087

  2. 在java中String类为什么要设计成final?

    大神链接:在java中String类为什么要设计成final? - 程序员 - 知乎 我进行了重新排版,并且更换了其中的一个例子,让我们更好理解. String很多实用的特性,比如说“不可变性”,是工 ...

  3. java中String类为什么要设计成final?

    1 将方法或类声明为final主要目的是:确保它们不会在子类中改变语义.String类是final类,这意味着不允许任何人定义String的子类. String基本约定中最重要的一条是immutabl ...

  4. 【笔记】在java中String类为什么要设计成final?

    部分内容转自知乎:https://www.zhihu.com/question/31345592 从自己的理解进行加工,压缩. String本质上是一个final类 public final clas ...

  5. Java中String类为什么被设计为final?

    Java中String类为什么被设计为final   首先,String是引用类型,也就是每个字符串都是一个String实例.通过源码可以看到String底层维护了一个byte数组:private f ...

  6. java里String类为何被设计为final

    前些天面试遇到一个非常难的关于String的问题,"String为何被设计为不可变的"?类似的问题也有"String为何被设计为final?"个人认为还是前面一 ...

  7. String类为什么被设计成不可变类

    1.享元模式: 1.共享元素模式,也就是说:一个系统中如果有多处用到了相同的一个元素,那么我们应该只存储一份此元素,而让所有地方都引用这一个元素. 2.Java中String就是根据享元模式设计的,而 ...

  8. 【JAVA零基础入门系列】Day11 Java中的类和对象

    今天要说的是Java中两个非常重要的概念--类和对象. 什么是类,什么又是对象呢?类是对特定集合的概括描述,比如,人,这个类,外观特征上,有名字,有年龄,能说话,能吃饭等等,这是我们作为人类的相同特征 ...

  9. Java中的类反射

    一.反射的概念 : 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力.这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它首先被程序 ...

随机推荐

  1. oracle服务器重启后无法进入系统,登录系统时提示model is unknow

    这个是因为安装oracle时,修改了一些系统参数,导致开机异常 在选择系统列表那里直接按e,进入系统开机配置 大概在倒数第二行,也就是有utf8那行,添加init=/bin/sh 然后ctrl+x重启 ...

  2. [转]web.xml中<url-pattern>详解

    标签<url-pattern><url-pattern>是我们用Servlet做Web项目时需要经常配置的标签,例: <servlet> <servlet-n ...

  3. 原生js实现的瀑布流布局

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. JFrame包含的容器(JRootPane)

    JFrame对象创建后,此对象包含JRootPane类型的容器.JRootPane 下有GlassPane,  和  LayeredPane,LayeredPane下又有ContentPane ,   ...

  5. SqlServer语句

    1.增加列 增加int列,不为空并赋默认值为0 alter table Department add Status int not null default 0 with values 2.新建表:c ...

  6. 记录一次linux删除mysql

    service mysqld status service mysqld stop ps –ef | grep mysql perl-DBD-MySQL-4.013-3.el6.x86_64 //删除 ...

  7. CentOS6.4 添加nginx系统服务

    简介: Nginx安装完成后默认不会注册为系统服务,所以需要手工添加系统服务脚本.在/etc/init.d目录下新建nginx文件,并更改权限其即可. 1.新建nginx文件 1.1.新建文件:vi ...

  8. SPI初识

    SPI初识 1.信息来源 2.需要了解的是SPI(x1,x2,x4)

  9. button高度改变

    代码:<input type="button" name="submit" value="submit" /> 利用css改变b ...

  10. 【巷子】---react-redux---【react】

    一.Redux与组件 react-redux是一个第三方插件使我们在react上更方便的来使用redux这个数据架构 React-Redux提供connect方法,用于从UI组件生成容器组件,conn ...