当前位置: 首页 > news >正文

String不得不说的那些事

一、String、StringBuilder和StringBuffer的区别

1. String是字符串常量,StringBuilder和StringBuffer是字符串变量

String对象创建完成之后,如果对其更改,都是重新创建一个字符串对象,让引用变量重新指向其引用地址,而StringBuilder和StringBuffer都是可变的;

2. StringBuilder是线程不安全的,StringBuffer是线程安全的

StringBuffer相关方法添加了线程同步关键字synchronize关键字,故线程安全的,但效率低比StringBuilder低。

二、String为什么设计成不可变(immutable)

1. 字符串常量池的优化需要

字符串常量池针对String字符串使用的一种优化策略,创建字符串对象前,先检查字符串常量是否已经有该字符串(obj1.equal(obj2)),有直接返回字符串在字符串常量池的引用,如果String为可变的,这种优化策略则无效;

2. 允许String对象缓存HashCode
字符串的不变性保证了hashcode唯一性,不可变的hashcode可以被缓存而不用重新计算,提升了像使用String作为键值的hashmap的效率,这也侧面反映了hashmap为什么多数使用String作为键值的原因了;

3. 多线程使用安全性

字符串不可变,所以在多线程可以共享一个字符串实例,而不需要做额外的线程同步;

4. 类加载器需要

类加载器用到字符串,不可变性提供了安全性,以便类的正确加载;例如在加载java.sql.Connection类,如果这个值被改成myhacked.Connection,则会对数据库造成不可知的破坏;

5. 安全性

如果字符串是不可变的,则会引起很严重的安全问题;例如数据库的用户名和密码都是以字符串形式传入获得数据库的连接,socket编程中,主机名等都是以字符串形式传入,如果字符串可变,黑客可以很容易改变字符串对象的值,造成安全漏洞。

三、String直接创建对象(String s="abc")和intern()方法的区别

两者在创建字符串对象先去字符串常量池查找,如果有,直接返回该字符串的引用,没有则在字符串常量池创建并返回引用,看上去两者无差别,但是这样那么intern存在的意义为何?

测试代码 Test.java

String s1 = "ab";
String s2 = "c";
String s3 = "abc";

System.out.println(s3=="ab"+"c");           //true
System.out.println(s3==s1+s2);              //false
System.out.println(s3==(s1+s2).intern());   //true

编译代码 Test.class

String s1 = "ab";
String s2 = "c";
String s3 = "abc";
System.out.println(s3 == "abc");
System.out.println(s3 == s1 + s2);
System.out.println(s3 == (s1 + s2).intern());

"ab"+"c";字符串拼接在编译期可以确定其值,进而可以在编译阶段确定该字符串是否存在于字符串常量池;但是s1+s2;字符串引用拼接需要在运行期才能得到结果,指望不上编译器的字符串常量池优化策略了,这时候intern方法作用便体现了,在运行期确定常量池是否有需要创建的字符串对象,如果有,返回其字符串常量池的引用。故得出的结论:String直接赋值和intern方法在字符串常量池的优化策略上,一个体现在编译期,一个则在运行期。

四、StringBuilder和"+"号的区别?

1. 拼接字符串常量

测试类

6 String s1 = "a" + "b" + "c";
7 String s2 = new StringBuilder().append("a").append("b").append("c").toString();

编译class

String s1 = "abc";
String s2 = "a" + "b" + "c";

字节件ByteCode

L0
 LINENUMBER 6 L0
 LDC "abc"
 ASTORE 1
L1
 LINENUMBER 7 L1
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 LDC "a"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 LDC "b"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 LDC "c"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 2

使用“+”进行字符串常量的拼接在编译时就已经完成,而使用 StringBuilder 进行字符串拼接需要在运行时完成。所以单纯的字符串常量拼接“+”的效率 应该高于 StringBuilder

2. 拼接字符串和引用

测试类

6 String s1 = "a";
7 String s2 = new StringBuilder().append(s1).append("b").append("c").toString();
8 String s3 = s1 + "b" + "c";

编译class

String s1 = "a";
String s2 = s1 + "b" + "c";
String s3 = s1 + "bc";

字节码ByteCode

L0
 LINENUMBER 6 L0
 LDC "a"
 ASTORE 1
L1
 LINENUMBER 7 L1
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 ALOAD 1
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 LDC "b"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 LDC "c"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 2
L2
 LINENUMBER 8 L2
 NEW java/lang/StringBuilder
 DUP
 INVOKESPECIAL java/lang/StringBuilder.<init> ()V
 ALOAD 1
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 LDC "bc"
 INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
 INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
 ASTORE 3

从字节码可以看出“+”拼接的字符串引用底层还是使用StringBuilder

参考链接

Java中的String,StringBuilder,StringBuffer三者的区别?

java中String类为什么不可变?

java String中的intern和String a="abc"的区别是什么?

转载于:https://www.cnblogs.com/bloghxr/p/10230368.html

相关文章:

  • 利用React 16.6新特性优化应用性能
  • ajax的19道经典面试题
  • 大数据就业前景,分析的太到位了
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • 程序员的本质
  • matlab练习程序(直方图匹配)
  • TortoiseSvn介绍
  • C#中Monitor和Lock以及区别
  • HDU 1575 Tr A (矩阵乘法)
  • MVC使用基架添加控制器出现的错误:无法检索XXX的元数据
  • 从程序员的视角揭秘Silverlight
  • oracle索引再论
  • Android应用开发学习笔记之多线程与Handler消息处理机制
  • jquery $.each() 小探
  • HDU 4089 Activation
  • 【399天】跃迁之路——程序员高效学习方法论探索系列(实验阶段156-2018.03.11)...
  • 【知识碎片】第三方登录弹窗效果
  • 2017前端实习生面试总结
  • Elasticsearch 参考指南(升级前重新索引)
  • java8 Stream Pipelines 浅析
  • java8-模拟hadoop
  • Js基础知识(四) - js运行原理与机制
  • node.js
  • PHP CLI应用的调试原理
  • PHP 使用 Swoole - TaskWorker 实现异步操作 Mysql
  • ViewService——一种保证客户端与服务端同步的方法
  • vue-cli在webpack的配置文件探究
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 包装类对象
  • 反思总结然后整装待发
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 机器学习中为什么要做归一化normalization
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 浅谈Golang中select的用法
  • 实战:基于Spring Boot快速开发RESTful风格API接口
  • 思维导图—你不知道的JavaScript中卷
  • ​决定德拉瓦州地区版图的关键历史事件
  • # Python csv、xlsx、json、二进制(MP3) 文件读写基本使用
  • #Spring-boot高级
  • #我与Java虚拟机的故事#连载15:完整阅读的第一本技术书籍
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (4)事件处理——(7)简单事件(Simple events)
  • (Python第六天)文件处理
  • (SpringBoot)第七章:SpringBoot日志文件
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转)重识new
  • (转)自己动手搭建Nginx+memcache+xdebug+php运行环境绿色版 For windows版
  • (转载)Google Chrome调试JS
  • .net 7 上传文件踩坑
  • .NET 设计模式—简单工厂(Simple Factory Pattern)
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .net反编译的九款神器
  • .stream().map与.stream().flatMap的使用