StringBuilder && StringBuffer原理浅析

本文主要以简单的String/StringBuilder/StringBuffer操作来看这三个类的实现原理。
什么简单操作呢?那就是StringBuilder与StringBuffer的append() && toString()两个方法。
示例代码如下:

public class TestStringBuffer_Builder {

    public static void main(String[] args) {
        TestStringBuffer_Builder testStringBuffer_builder = new TestStringBuffer_Builder();
        testStringBuffer_builder.testStringBuilder();
        testStringBuffer_builder.testStringBuffer();
    }

    public void testStringBuilder()
    {
        String strName = new String("JackMa");
        String strCountry = new String("China");

        StringBuilder stringBuilder = new StringBuilder(64);
        stringBuilder.append("Name:").append(strName).append("\n");
        stringBuilder.append("Country:").append(strCountry).append("\n");

        System.out.print(stringBuilder.toString());
    }

    private void testStringBuffer()
    {
        String strName = new String("JackMa");
        String strCountry = new String("China");

        StringBuffer stringBuffer = new StringBuffer(64);
        stringBuffer.append("Name:").append(strName).append("\n");
        stringBuffer.append("Country:").append(strCountry).append("\n");

        System.out.print(stringBuffer.toString());
    }
}

以上的demo中,涉及到了String的构造,StringBuilder & StringBuffer的构造、append与toString。我们分别研究这几个方法,来了解其内部的实现原理。

一、String
代码中首先构造了String。
先简单看看String内部发生了什么:

public final class String
{
	private final char value[];
	private int hash;

	public String() {
		this.value = "".value;
	}

	public String(String original) {
		this.value = original.value;
		this.hash = original.hash;
	}

	public String(char value[]) {
		this.value = Arrays.copyOf(value, value.length);
	}

	public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
}

可以看的出来,String中的数据都是保存在数组char value[]中。
对于String的concat(拼接)过程可以看出,最后生成了一个新的String对象作为拼接的结果。

  

二、StringBuilder
先看看StringBuilder中的方法:

public class StringBuilder
		extends AbstractStringBuilder
{
	public StringBuilder(int capacity) {
		super(capacity);
	}

	public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}
父类:
public abstract class AbstractStringBuilder
{
	char[] value;

	AbstractStringBuilder(int capacity) {
		value = new char[capacity];
	}

	public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

	private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0)
            expandCapacity(minimumCapacity);
    }

	void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    }

	public String toString() {
        // Create a copy, don‘t share the array
        return new String(value, 0, count);
    }
}

  

StringBuilder中也是用数组进行数据保存。相比于String的concat操作,StringBuilder在拼接字符串的过程始终是一个对象在操作,变化的是StringBuilder内部的数组若容量不够,则进行扩充。
扩容算法中,在拼接字符串不长的情况下,容量通常扩为2倍。若2倍不足,则扩为需要的大小。
在toString方法中,使用StringBuilder内部的value数组构造一个新的的String对象,并返回。

三、StringBuffer

public final class StringBuffer
		extends AbstractStringBuilder
{
	private transient char[] toStringCache;

	public synchronized StringBuffer append(String str)
	{
		toStringCache = null;
		super.append(str);
		return this;
	}

	public synchronized String toString() {
        if (toStringCache == null) {
            toStringCache = Arrays.copyOfRange(value, 0, count);
        }
        return new String(toStringCache, true);
    }
}

  

StringBuffer中,也是用数组进行字符串数据保存。不同于StringBuilder,StringBuffer中的操作字符串方法是同步的,因此属于线程安全类。
同时用了transient char[] toStringCache来缓存数据。在调用toString时,将字符串内容保存进toStringCache, 且在修改StringBuffer时(例如append、insert、delete等字符操作),清空该缓存。
若字符串无修改,在第二次调用toString时直接将缓存内容返回,从而提升字符转换效率。

这里面涉及到一个点:用于缓存字符内容的数组toStringCache是用transient修饰,直接访问内存,从而实现线程间的可见性。具体内容可进一步了解关键字transient。

原文地址:https://www.cnblogs.com/xinxinBlog/p/10176838.html

时间: 2024-10-21 20:36:22

StringBuilder && StringBuffer原理浅析的相关文章

【Spark Core】TaskScheduler源码与任务提交原理浅析2

引言 上一节<TaskScheduler源码与任务提交原理浅析1>介绍了TaskScheduler的创建过程,在这一节中,我将承接<Stage生成和Stage源码浅析>中的submitMissingTasks函数继续介绍task的创建和分发工作. DAGScheduler中的submitMissingTasks函数 如果一个Stage的所有的parent stage都已经计算完成或者存在于cache中,那么他会调用submitMissingTasks来提交该Stage所包含的Tas

Handler原理浅析

    理解Handler的原理首先要搞清楚什么是Looper,在我的上一篇博文中对此有专门的介绍.Looper的作用是开启一个消息循环,从MessageQueue(Message队列,是Looper的成员变量)中循环取出消息处理.一个线程要使用Handler来处理来自其它线程的消息,这个线程必须有且仅有一个Looper对象与之绑定,也可以说一个Looper对象是是与一个线程一一对应的. Hander有一个Looper类型的成员,在Handler的构造函数(new Handler()或者new

微信QQ的二维码登录原理浅析

在很多地方就是都出现了使用二维码登录,二维码付款,二维码账户等应用(这里的二维码种马,诈骗就不说了),二维码验证,多终端辅助授权应用开始多起来,这里先说下啥是二维码,其实二维码就是存了二进制数据的黑白图片,当出现要求二维码登录的时候,服务器会生成一条临时的唯一的二维码信息,发送到客户端以二维码(图片)的形式写入到网页,然后你就会看到统一的四个方形的二维码,如果做的好这个二维码信息应该是有时效的,这里暂且不考虑这些,就简单的微信登录作为例子看看吧: 首先说下整个授权流程: 在客户端网页中会不断向服

LINQ内部执行原理浅析

C#3.0 增加LINQ的特性 一.基本概念 LINQ,语言级集成查询(Language INtegrated Query) 经过了最近 20 年,面向对象编程技术( object-oriented (OO) programming technologies )在工业领域的应用已经进入了一个稳定的发展阶段.程序员现在都已经认同像类(classes).对象(objects).方法(methods)这样的语言特性.考察现在和下一代的技术,一个新的编程技术的重大挑战开始呈现出来,即面向对象技术诞生以来

String Stringbuilder Stringbuffer的区别

String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以

[转] 深入探究 String 与 StringBuilder 内部原理

转自:深入探究 String 与 StringBuilder 内部原理 System.String 类型一直是我们不断讨论的话题,它是一个用于对字符串进行存储和操作的这么一个类型. System.String 也是 C# 基础类型中唯一的引用类型.但是,它却具有很多值类型的特点. 我们来看一段简单的代码: 1 string text = "White"; 2 string temp = text; 3 temp = "Black"; 4 Console.WriteL

String,StringBuilder,StringBuffer三者的区别

1.三者在执行速度方面的比较:StringBuilder >  StringBuffer  >  String 2.String <(StringBuffer,StringBuilder)的原因 String:字符串常量 StringBuffer:字符串变量 StringBuilder:字符串变量 从上面的名字可以看到,String是"字符创常量",也就是不可改变的对象.对于这句话的理解你可能会产生这样一个疑问  ,比如这段代码: 1 String s = "

iOS 关于微信检测SDK应用的原理浅析

微信作为一个开放平台,各方面都是做得比较好的,推出了SDK之后,微信与使用了SDK的应用便能进行更多交互.但在iOS平台上,应用间交换数据还是相对麻烦的,那么微信为什么能直接在应用检测到其他使用了SDK的应用呢?基于这个疑问,我用了一个下午研究其原理. 一.SDK的方法 我之前也没使用过微信的SDK,不过下载后,查看发现SDK接口有这么一段 1 /*! @brief WXApi的成员函数,在微信终端程序中注册第三方应用. 2 * 3 * 需要在每次启动第三方应用程序时调用.第一次调用后,会在微信

如何在App中实现朋友圈功能之一朋友圈实现原理浅析——箭扣科技Arrownock

如何在App中实现朋友圈功能 之一 朋友圈实现原理浅析 微信朋友圈.新浪微博.知乎等知名朋友圈类型功能,大家有没有想过其实现的逻辑呢? 本文以微信朋友圈功能为例,解析实现逻辑. 朋友圈的结构: 朋友圈从总体上来说会分为6块结构,分别是墙.用户.图片.墙贴.评论与点赞. 墙:一块公共的墙,所有的墙贴都位于其上,如果APP只实现朋友圈功能,那么墙贴其实是可以不用的,但是如果APP要实现朋友圈.新闻圈等等其他各种墙贴类型消息的话,那么墙就显得很有必要了,这时候我们需要通过建立不同的墙来展示不同类型的墙