zoukankan      html  css  js  c++  java
  • 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("
    ");
            stringBuilder.append("Country:").append(strCountry).append("
    ");
    
            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("
    ");
            stringBuffer.append("Country:").append(strCountry).append("
    ");
    
            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。

  • 相关阅读:
    大话数据结构笔记——第二章 算法
    大话数据结构笔记——第一章 数据结构绪论
    Vue学习笔记【33】——nrm的安装使用
    Vue学习笔记【33】——相关文章
    flag-icon-css
    谷歌浏览页面常用快捷键
    PHPStorm IDE 快捷键(MAC版)
    npm install报错类似于npm WARN tar ENOENT: no such file or directory, open '*** ode_modules.staging***
    lodash
    Docker学不会?不妨看看这篇文章
  • 原文地址:https://www.cnblogs.com/xinxinBlog/p/10176838.html
Copyright © 2011-2022 走看看