最近突然被问到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. centos 7 lvs 负载均衡搭建部署

    环境: 在vm里开三个虚拟机 负载调度器:10.0.3.102 真实服务器1:10.0.3.103 真实服务器2:10.0.3.104 虚拟ip: 10.0.3.99 (用来飘移) 负载调度器上 if ...

  2. Introducing Makisu: Uber’s Fast, Reliable Docker Image Builder for Apache Mesos and Kubernetes

    转自:https://eng.uber.com/makisu/?amp To ensure the stable, scalable growth of our diverse tech stack, ...

  3. [转载] IIS来搭建一个只能实现基本功能的FTP服务器

    转自  http://blog.sina.com.cn/s/blog_3f7e47f20100haur.html 本文介绍通过win7自带的IIS来搭建一个只能实现基本功能的FTP服务器,第一次装好W ...

  4. Kafka 文件存储机制那些事 - 美团技术团队

    出处:https://tech.meituan.com/2015/01/13/kafka-fs-design-theory.html 自己总结: Kafka 文件存储机制_结构图:https://ww ...

  5. vue-loader v15、vue-loader v14及之前版本,配置css modules的区别

    vue-loader v15 配置css modules: 是在 css-loader 里配置 官方文档:https://vue-loader.vuejs.org/zh/migrating.html# ...

  6. PHP 换行符 PHP_EOL

    PHP 中换行可以用 PHP_EOL 来替代,以提高代码的源代码级可移植性: unix系列用 \n windows系列用 \r\n mac用 \r <?php echo PHP_EOL; //w ...

  7. Linux 下Tomcat单机多应用

    修改/etc/profile 下,增加如下两个tomcat的配置.apache-tomcat-8.0.50为第一个tomcat, apache-tomcat-8.0.50_2为第二个tomcat ex ...

  8. Apache Kafka监控之Kafka Web Console

    Kafka Web Console:是一款开源的系统,源码的地址在https://github.com/claudemamo/kafka-web-console中.Kafka Web Console也 ...

  9. 简单说throw和throws的区别

    1. 区别 throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是指抛出的一个具体的异常类型. 2.分别介绍 ...

  10. python的命令行参数处理

      import argparse # A position argument func_choice = {'client' : 'client function', "server&qu ...