关于数组、String、ArrayList的一点总结

Java容器:String/StringBuffer/ArrayList详解与底层扩容机制
本文详细解析了Java中String、StringBuffer和ArrayList的底层实现,重点讨论了它们如何使用数组存储数据、空参构造器的默认容量、有参构造器的容量计算以及扩容策略。了解这些有助于掌握它们的工作原理和高效使用方法。

String、ArrayList可以看做是存储数据的容器,底层都是使用数组来存储数据的

String

String底层存储数据是char[ ] value

当空参构造器创建对象时

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

此时char[ ] value = new char[ 0 ];
这个一般都不使用,感觉没多大意义。

常见的是通过有参构造器来创建对象
比如:

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

当 执行代码 String str = new String("123");时,对象str的char[ ] value = new char[]{'1','2','3'};

StringBuffer

和String一样,StringBuffer底层存储数据也是char[ ] value

当空参构造器创建对象时

public StringBuffer() {
  super(16);
}

调用父类构造器

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

也就是char[] value = new char[16];
怎么去记忆16这个数字呢?
因为char是2byte(字节)=16bit (位)

接着如果使用有参构造器创建对象,比如:

public StringBuffer(String str) {
    super(str.length() + 16);
    append(str);
}

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

调用父类的append(str)方法
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) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}

private int newCapacity(int minCapacity) {
  // overflow-conscious code
   int newCapacity = (value.length << 1) + 2;
   if (newCapacity - minCapacity < 0) {
       newCapacity = minCapacity;
   }
   return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
       ? hugeCapacity(minCapacity)
       : newCapacity;
}

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
        if (srcBegin < 0) {
            throw new StringIndexOutOfBoundsException(srcBegin);
        }
        if (srcEnd > value.length) {
            throw new StringIndexOutOfBoundsException(srcEnd);
        }
        if (srcBegin > srcEnd) {
            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
        }
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
    }

一眼就能看出来了,char[] value = new char[ str.length + 16];
当value数组容量不够存储时,就会扩容

(value.length << 1) + 2;

原有的数组容量*2倍+2作为新数组的容量,再将原数组的所有元素都复制到新数组中。

str.getChars(0, len, value, count);

将参数字符串添加到value数组中的最末尾。

StringBuffer是可变的,它有一个非常常用的方法,就是append(String str),它也是调用父类的重载方法,在上面也出现过。


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

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;
}

注意它一直返回的都是调用这个方法的对象本身,所以可以一直调用append(String str);挺方便的。

StringBuffer sb = new StringBuffer();
System.out.println(sb.length());//0
StringBuffer sb2 = sb.append("123");
System.out.println(sb == sb2);//true 内存地址相同,说明引用指向同一个StringBuffer对象
System.out.println(sb.length());//3

StringBuilder

与StringBuffer的底层逻辑一样,只不过StringBuffer底层使用了synchronized 关键字修饰方法,保证了线程安全,但效率就降低了。
而StringBuilder是线程不安全的,效率高一些。

ArrayList

ArrayList底层存储数据是Object[ ] elementData;

最常用的就是调用空参构造器创建对象ArrayList list = new ArrayList();

  1. Java的JDK7及之前
public ArrayList() {
  this(10);
}

public ArrayList(int initialCapacity) {
  ...
  this.elementData = new Object[initialCapacity];
}

使用空参构造器创建对象,底层Object[ ] elementData = new Object[10];

然后添加数据,调用add()

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public boolean add(E e) {
   ensureCapacityInternal(size + 1);  // Increments modCount!!
   elementData[size++] = e;
   return true;
}

private void ensureCapacityInternal(int minCapacity) {
  ...
  if (minCapacity > elementData.length > 0 ) {
       grow(minCapacity);
   }
}

private void grow(int minCapacity){
	int oldCapacity = elementData.length;
	int newCapacity = oldCapacity + (oldCapacity >> 1);
	if(newCapacity - minCapacity < 0){
		newCapacity = minCapacity;
	}
	...
	elementData = Arrays.copyOf(elementData,newCapacity);
}

当第一次添加元素,list.add(123);,底层就是elementData[0] = new Integer(123);
当已经添加了10个元素,达到了elementData的容量,当添加第11个元素时,底层发现容量不足,就自动扩容,int newCapacity = oldCapacity + (oldCapacity >> 1); 表示默认情况下新数组的容量为原数组容量的1.5倍。

elementData = Arrays.copyOf(elementData,newCapacity);

表示将原数组的所有元素都复制到新数组中。

2. Java的JDK8
空参构造器创建对象ArrayList list = new ArrayList();

private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

public ArrayList() {
  this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

对象的Object[ ] elementData = {};也就是创建一个空的Object数组。

然后添加数据,调用add()

private static final int DEFAULT_CAPACITY = 10;

public boolean add(E e) {
   ensureCapacityInternal(size + 1);  // Increments modCount!!
   elementData[size++] = e;
   return true;
}

private void ensureCapacityInternal(int minCapacity) {
  if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
       minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
   }

   ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
  modCount++;

   // overflow-conscious code
   if (minCapacity - elementData.length > 0)
       grow(minCapacity);
}

private void grow(int minCapacity) {
    // overflow-conscious code
    int oldCapacity = elementData.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
}

第一次add()添加元素,ensureCapacityInternal(size + 1);检查到elementData数组容量不足,扩容为长度为10的Object[ ],下次扩容和JDK7中一样,新建数组,其容量是原数组的1.5倍,然后将原数组的所有元素复制到新数组中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值