【String】

首先,从String类的定义入手,可以看到String类是由final修饰,即不可变的,一旦创建出来就不可修改,因此首先明确,字符串的拼接、截取等操作都会产生新的字符串对象。

观察以下几种创建Stirng的语句

1 String s1 = "hello ";
2 String s2 = "world";
3 String s3 = s1 + s2;
4 String s4 = "hello " + "world";
5 String s5 = new String("hello world");

1> 对于s1,直接通过字符串常量创建,会先查找常量池中是否有 hello 这个字符串,有的话不创建,没有的话新建,因此会在常量池中创建一个对象。

2> 对于s2,同上,在常量池中创建一个对象。

3> 对于s3,字符串拼接操作,查看反汇编代码,字符串拼接实际上是new StringBuilder(),然后执行其append()方法,最后执行toString,过程中创建了3个对象。

4> 对于s4,直接通过常量字符串拼接,会被优化为创建 hello world,在常量池中创建对象。

5> 对于s5,new操作一定会在堆中创建对象,然后查找常量池中是否有 hello world 这个字符串,没有就在常量池中创建一个。

对于s3、s4、s5,字符串的内容都是hello world,但对于s3和s5,引用的都是堆中创建的字符串对象,s4引用的则直接是常量池中的对象,因此它们三个的引用都是不同的,如下

intern

通过上面的验证,知道直接通过常量定义的String对象是位于常量池中,而通过new显式创建或者拼接隐式创建的String对象是位于堆中。

除了常用的操作字符串方法,JDK还提供了 inter() 方法,该方法的官方说明如下,作用是当方法调用时,如果常量池中已经包含一个和这个String相等(内容相同,即equals方法)的String,就会返回常量池中的对象,否则,这个对象会被添加到常量池,然后返回她的引用。简单来说其作用是把字符串缓存到常量池中。

通过几个例子来验证intern的作用

【StringBuilder和StringBuffer】

StringBuilder和StringBuffer都表示可变的字符串序列,可以通过其提供的一序列方法实现字符串的拼接、截取,观察源码会发现两个类的核心代码基本一致,二者都继承自抽象类AbstractStringBuilder。

  • 二者的共同点是均提供了字符串的拼接、截取等操作,无需每次变动都创建新的对象,一次创建,最后只需通过toString生成最终的字符串对象即可。

  • 二者的区别在于在字符串拼接等操作上StringBuffer使用synchronized关键字修饰方法,多线程情况下保证了线程安全,当然相比StringBuilder,也降低了性能。

通过源码来看动态拼接字符串逻辑,StringBuilder和StringBuffer都是调用父类的append方法实现,因此二者实现逻辑是一致的,其中count是用来记录value数组已经使用的长度,即在现有的value数组后面拼接上新的str字符串。因此在StringBuilder中,代码中的 count+=len 不是原子操作,多线程操作的情况下,例如当前count为5,可能出现多个线程拿到的count都是5,分别执行累加操作后再赋给count,得到的count只是6,此时便出现了线程不安全的情况。

附:虽然上面提到,通过 + 号拼接String对象时,java也会隐式地创建StringBuilder对象进行拼接,通常情况下并不会造成性能效率损失,但在需要大量循环拼接字符串时,使用+拼接,会在每次循环时都创建一个StringBuilder对象,循环结束后,内存中会多出许多无用的StringBuilder对象,因此这种情况,建议在循环体外创建StringBuilder对象,循环调用其append()方法拼接,如此只需创建一个StringBuilder对象。

扩容

首先注意二者的初始容量都是16,当然也可以通过参数指定初始容量

1 public StringBuilder() {
2 super(16);
3 }
4 public StringBuffer() {
5 super(16);
6 }

在字符串拼接时,都会调用父类AbstractStringBuilder的append方法,方法源码如下

 1 public AbstractStringBuilder append(String str) {
2 if (str == null) {
3 return appendNull();
4 }
5 int len = str.length();
6 ensureCapacityInternal(count + len);
7 putStringAt(count, str);
8 count += len;
9 return this;
10 }

其中的 ensureCapacityInternal 方法,就是在拼接前进行扩容

1 private void ensureCapacityInternal(int minimumCapacity) {
2 // overflow-conscious code
3 int oldCapacity = value.length >> coder;
4 if (minimumCapacity - oldCapacity > 0) {
5 value = Arrays.copyOf(value,
6 newCapacity(minimumCapacity) << coder);
7 }
8 }

其中的minimumCapacity就是扩容后的字符串长度,超过目前容量的话,调用newCapacity方法执行扩容,可以看出每次扩容后的容量是原容量的2倍加2,如果仍不够,就直接扩容到需要的长度。

 1 private int newCapacity(int minCapacity) {
2 // overflow-conscious code
3 int oldCapacity = value.length >> coder;
4 int newCapacity = (oldCapacity << 1) + 2;
5 if (newCapacity - minCapacity < 0) {
6 newCapacity = minCapacity;
7 }
8 int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
9 return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
10 ? hugeCapacity(minCapacity)
11 : newCapacity;
12 }

【Java】String、StringBuilder和StringBuffer的更多相关文章

  1. java String,StringBuilder和StringBuffer

    String:1.java语言中的字符串值属于String类,虽然有其它方法表示字符串(如字符数组),但java一般使用Sting类作为字符串的标准格式,java编译器把字符串值作为String对象. ...

  2. 全面解释java中StringBuilder、StringBuffer、String类之间的关系

    StringBuilder.StringBuffer.String类之间的关系 java中String.StringBuffer.StringBuilder是编程中经常使用的字符串类,在上一篇博文中我 ...

  3. 【转载】关于Java String, StringBuilder, StringBuffer, Hashtable, HashMap的面试题

    REF: http://blog.csdn.net/fightforyourdream/article/details/15333405 题目是一道简单的小程序,像下面这样:[java] view p ...

  4. Java中String, StringBuilder和StringBuffer

    Java中常用来处理字符串的类有三个: String, StringBuffer和StringBuilder. 区别 三者都继承自CharSequence接口, 首先说明三者间主要区别 String字 ...

  5. Java基础学习总结(65)——Java中的String,StringBuilder和StringBuffer比较

    字符串,就是一系列字符的集合. Java里面提供了String,StringBuffer和StringBuilder三个类来封装字符串,其中StringBuilder类是到jdk 1.5才新增的.字符 ...

  6. java中StringBuilder、StringBuffer、String类之间的关系

    今天在CSDN的高校俱乐部里看到了"Java基础水平測试(英文)".感觉自己学了java这么久,想看下自己的java水平究竟是个什么样.測试结果就不说了,反正是慘不忍睹. 看了一下 ...

  7. java 常用类库:String ; StringBuilder和StringBuffer类

    1. String 1.String对象是不可变的 String类的value属性是用来存放字符串里面的值的.这个属性是被final修饰的.final修饰的变量不能够被第二次赋值,所以字符串是不可变的 ...

  8. Java String StringBuilder StringBuffer

    String是字符串常量 StringBuilder和StringBuffer都是字符串变量 速度方面:StringBuilder > StringBuffer > String 每当用S ...

  9. String StringBuilder以及StringBuffer

    例一:[看了威哥视频,下面更好理解] package sunjava; public class String_test { public static void main(String[] args ...

  10. String,StringBuilder和StringBuffer的特点和使用场景

    这三个类是平时开发中经常遇到的,主要差别是运行速度和线程安全,使用起来String最方便了,另外两个稍微复杂一些. 从运行速度角度看,StringBuilder>StringBuffer> ...

随机推荐

  1. DCL之单例模式

    所谓的DCL 就是 Double Check Lock,即双重锁定检查,在了解DCL在单例模式中如何应用之前,我们先了解一下单例模式.单例模式通常分为"饿汉"和"懒汉&q ...

  2. const成员函数可以将非const指针作为返回值吗?

    先给出一段代码 class A { int *x; public: int *f() const { return x; } }; 成员函数f返回指向私有成员 x 的非常量指针,我认为这会修改成员x ...

  3. 《C++ Primer》笔记 第10章 泛型算法

    迭代器令算法不依赖于容器,但算法依赖于元素类型的操作. 算法永远不会执行容器的操作.算法永远不会改变底层容器的大小. accumulate定义在头文件numeric中,接受三个参数,前两个指出需要求和 ...

  4. MySQL 异常有这一篇就够了!

    摘要:在本文中,总结了开发过程中最为常见的几种 MySQL 抛出的异常以及如何解决,包括高版本驱动的问题.时区配置问题.SSL 连接问题等,是一篇经验总结贴. 前言 在本文中,总结了开发过程中最为常见 ...

  5. React开发入门:以开发Todo List为例

    目录 概述 React基本概念 JSX是什么? 设置React APP 初始化APP 应用结构 探索第一个React组件 index.js 变量和props JSX中的变量 组件props props ...

  6. C语言入门-mingw64安装+配置

    OK,大家好,结合上期所说,本期让我们来配置编译器吧! 首先先下载mingw64离线包,官网下载慢,可以去群里下载,*.7z格式(有些同学可能没有解压软件,为了照顾这部分同学,笔者提供*.exe格式的 ...

  7. 2019HDU多校第七场 HDU6651 Final Exam

    一.题目 Final Exam 二.分析 题目说的比较绕,总之一定要记住,$n$个题目都可以做,至少作对$k$到,但是做题目的人不知道每道题对应的分数. 作为出题人,如果他是田忌,肯定不会去在做题目的 ...

  8. 翻译:《实用的Python编程》06_02_Customizing_iteration

    目录 | 上一节 (6.1 迭代协议) | 下一节 (6.3 生产者/消费者) 6.2 自定义迭代 本节探究如何使用生成器函数自定义迭代. 问题 假设你想要自定义迭代模式. 例如:倒数: >&g ...

  9. 2、Spring教程之HelloSpring

    导入Jar包 注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 . <dependency> <grou ...

  10. Genymotion下载模拟器慢

    •问题来源 Genymotion 是个很不错的 Android 模拟器,系统更新快,启动速度快: 但是服务器在国外,Android 镜像下载起来那个速度就不敢恭维了: 当然如果你可以[科学,上网]就另 ...