一、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"的区别是什么?

String不得不说的那些事的更多相关文章

  1. 【原创】关于DNS不得不说的一些事

    引言 今天我们来聊聊DNS. 所谓域名系统(Domain Name System缩写DNS,Domain Name被译为域名)是因特网的一项核心服务,它作为可以将域名和IP地址相互映射的一个分布式数据 ...

  2. String类基础的那些事!

    第三阶段 JAVA常见对象的学习 第一章 常见对象--String类 (一) String 类的概述及其构造方法 (1) 概述 多个字符组成的一串数据,例如 "abc" 也可以看成 ...

  3. 【转】关于DNS不得不说的一些事

    转自:https://www.cnblogs.com/rjzheng/p/11395695.html 引言 今天我们来聊聊DNS.所谓域名系统(Domain Name System缩写DNS,Doma ...

  4. 我和ip_conntrack不得不说的一些事

    面对让人无语的ip_conntrack,我有一种说不出的感觉!自从接触它到现在,已经两年多了,其间我受到过它的恩惠,也被它蹂躏过,被它玩过,但是又不忍心舍弃它,因为我找不到更好的替代.工作中,学习中, ...

  5. Session与Cookie间不得不说的一些事

    在很久很久以前,刚有浏览器和网页的时候,web开发者发现了一个问题,我必须要在客户端这边保存一些东西才能实现某些功能,比如大家喜闻乐见的购物车.用户登录.自动登陆等.但是客户端只有一个浏览器,怎么在用 ...

  6. 镜像仓库管理:与Portus不得不说的那些事

    背景: 目前在做一个云计算相关的项目,其中有这样一个需求:每个平台用户都有自己的docker镜像仓库(docker registry),用户可以对自己的镜像仓库的push/pull权限进行管理,也就是 ...

  7. 《java入门第一季》之类(String类常见方法小叙)

    String类下面的构造方法和一些常见的方法: /* * 字符串:就是由多个字符组成的一串数据.也可以看成是一个字符数组. * 通过查看API,可以知道 * A:字符串字面值"abc&quo ...

  8. Java 枚举那点事

    目录 最近有需求,想存自定义的枚举值,比如 HOTLINE("Hotline") 我想存 Hotline 于是研究了一下Java的枚举问题 如下数据库的Entity (贫血模型哈) ...

  9. 关于javaScript事件委托的那些事

    今天是第一次写稿,还是有那么一丢丢小鸡冻...回归正题啦... 关于javaScript事件委托不得不说的那些事,为什么要使用事件委托? 我们可以这么说,假设老板要分配一项任务,首先要秘书叫A君来到办 ...

随机推荐

  1. DocumentType类型

    并不常用 nodeType 10 nodeName doctype的名称 NodeValue 值为null parentNode Document 不支持子节点 DocumentType不能动态创建, ...

  2. SQL编写-谁和谁是好朋友

    problem: 用户表 姓名 张三 李四 王五       好友表   姓名 好友姓名 张三 李四 张三 王五 李四 张三 用户表里面姓名必须在好友表里面互加为好友,请问如何找出还没有加为好友的姓名 ...

  3. 【慕课网实战】Spark Streaming实时流处理项目实战笔记七之铭文升级版

    铭文一级: 第五章:实战环境搭建 Spark源码编译命令:./dev/make-distribution.sh \--name 2.6.0-cdh5.7.0 \--tgz \-Pyarn -Phado ...

  4. Silverlight中关于ComboBox的各种使用

    前端放置了几个ComboBox的控件. <Grid x:Name="LayoutRoot" Background="White"> <Comb ...

  5. vue+大文件分片上传

    最近公司在使用vue做工程项目,实现大文件分片上传. 网上找了一天,发现网上很多代码都存在很多问题,最后终于找到了一个符合要求的项目. 工程如下: 对项目的大文件上传功能做出分析,怎么实现大文件分片上 ...

  6. 知识点:CSS代码语法

    css 样式由选择符和声明组成,而声明又由属性和值组成,如下图所示: 选择符:又称选择器,指明网页中要应用样式规则的元素,如本例中是网页中所有的段(p)的文字将变成蓝色,而其他的元素(如ol)不会受到 ...

  7. Java关联关系、依赖关系

    关联关系 概念:对象和对象之间的连接 定义:A类关联B类,指的是B类对象作为A类的属性存在,称为“has”关联关系 生命周期:如果A类关联B类,那么创建A类的对象时实例化B类的对象,直到A类对象被销毁 ...

  8. 第88讲:Scala中使用For表达式实现map、flatMap、filter

    今天我们来学习一下如何使用for表达式实现map.flatMap以及filter 首先,我们来看下map.map的功能是,传入一个list,通过一个函数f,将list中的元素A变成元素B的过程.最后得 ...

  9. E - Evaluate Matrix Sum

    Description Given a matrix, the elements of which are all integer number from 0 to 50, you are requi ...

  10. 设置UITableView分割线距左边的间距

    ``` [self.tableView setSeparatorInset:UIEdgeInsetsZero]; [self.tableView setLayoutMargins:UIEdgeInse ...