JAVA中的部分须要扩容的内容总结以下:
第一部分:java
HashMap<String, String> hmap=new HashMap<>();
HashSet<String> hset=new HashSet<>();
Hashtable<String, String> htable=new Hashtable<>();
第二部分:
CopyOnWriteArrayList<String> coarray=new CopyOnWriteArrayList<>();
ArrayList<String> array=new ArrayList<>();
Vector<String> vec=new Vector<>();
第三部分:
StringBuffer sb=new StringBuffer();
StringBuilder sbu=new StringBuilder();
先从如下几个源码方面分析:(JDK1.8)数组
一、初始容量。
二、扩容机制。
三、同类型之间对比。安全
1.1 HashMap:
1、初始容量定义:默认为1 << 4(16)。最大容量为1<< 30。
/**
* The default initial capacity - MUST be a power of two.
*/
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
/**
* The maximum capacity, used if a higher value is implicitly specified
* by either of the constructors with arguments.
* MUST be a power of two <= 1<<30.
*/
static final int MAXIMUM_CAPACITY = 1 << 30;
2、扩容加载因子为(0.75),第一个临界点在当HashMap中元素的数量等于table数组长度*加载因子(16*0.75=12),
若是超出则按oldThr << 1(原长度*2)扩容。
/**
* The load factor used when none specified in constructor.
*/
static final float DEFAULT_LOAD_FACTOR = 0.75f;
/**
* Constructs an empty <tt>HashMap</tt> with the default initial capacity
* (16) and the default load factor (0.75).
*/
if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold多线程
1.2 HashSet并发
1、初始容量定义:16。由于构造一个HashSet,其实至关于新建一个HashMap,而后取HashMap的Key。
扩容机制和HashMap同样。
public HashSet(Collection<? extends E> c) {
map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}app
1.3 Hashtable<String, String> htable=new Hashtable<>();
public class Hashtable<K,V>
extends Dictionary<K,V>
1、初始容量定义:capacity (11)。
/**
* Constructs a new, empty hashtable with a default initial capacity (11)
* and load factor (0.75).
*/
public Hashtable() {
this(11, 0.75f);
}
2、扩容加载因子(0.75),当超出默认长度(int)(11*0.75)=8时,扩容为old*2+1。
int newCapacity = (oldCapacity << 1) + 1;
小结:HashTable和HashMap区别性能
第一,继承不一样。
public class Hashtable extends Dictionary implements Map
public class HashMap extends AbstractMap implements Map
第二:
Hashtable 中的方法是同步的,而HashMap中的方法在缺省状况下是非同步的。在多线程并发的环境下,能够直接使用
Hashtable,可是要使用HashMap的话就要本身增长同步处理了。
第三,Hashtable中,key和value都不容许出现null值。ui
在HashMap中,null能够做为键,这样的键只有一个;能够有一个或多个键所对应的值为null。当get()方法返回null值时,
便可以表示 HashMap中没有该键,也能够表示该键所对应的值为null。所以,在HashMap中不能由get()方法来判断HashMap中
是否存在某个键, 而应该用containsKey()方法来判断。this
第四,两个遍历方式的内部实现上不一样。spa
Hashtable、HashMap都使用了 Iterator。而因为历史缘由,Hashtable还使用了Enumeration的方式 。
第五,哈希值的使用不一样,HashTable直接使用对象的hashCode。而HashMap从新计算hash值。
第六,
Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增长的方
式是 old*2+1。HashMap中hash数组的默认大小是16, 增长的方式是 old*2。
2.1 CopyOnWriteArrayList:
/**
* Creates an empty list.
*/
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
CopyOnWriteArrayList在作修改操做时,每次都是从新建立一个新的数组,在新数组上操做,最终再将新数组替换掉原数组
。所以,在作修改操做时,仍能够作读取操做,读取直接操做的原数组。读和写操做的对象都不一样,所以读操做和写操做互
不干扰。只有写与写之间须要进行同步等待。另外,原数组被声明为volatile,这就保证了,一旦数组发生变化,则结果对
其它线程(读线程和其它写线程)是可见的。
CopyOnWriteArrayList并不像ArrayList同样指定默认的初始容量。它也没有自动扩容的机制,而是添加几个元素,长度就相
应的增加多少。
CopyOnWriteArrayList适用于读多写少,既然是写的状况少,则不须要频繁扩容。而且修改操做每次在生成新的数组时就指
定了新的容量,也就至关于扩容了,因此不须要额外的机制来实现扩容。
2.2 ArrayList<String> array=new ArrayList<>();
1、初始容量定义:10。
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
2、扩容:oldCapacity + (oldCapacity >> 1),即原集合长度的1.5倍。
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
2.3 Vector<String> vec=new Vector<>();
1、初始容量定义:10。
public Vector() {
this(10);
}
2、扩容:当扩容因子大于0时,新数组长度为原数组长度+扩容因子,不然新数组长度为原数组长度的2倍。
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
小结:
1,ArrayList与Vector初始容量都为10。
2,扩容机制不一样,当超出当前长度时ArrayList扩展为原来的1.5倍,而若不考虑扩容因子Vector扩展为原来的2倍。
3,ArrayList为非线程安全的,处理效率上较Vector快,若同时考虑线程安全和效率,可使用 CopyOnWriteArrayList。
3.1 StringBuffer sb=new StringBuffer();
1、初始容量定义:16。
public StringBuffer() {
super(16);
}
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
2、扩容:由于StringBuffer extends AbstractStringBuilder,因此其实是用的是AbstractStringBuilder
的扩容方法,当用append(str),添加字符串时,假设字符串中已有字符长度为count的字符串,初始长度value=16,若要添加的
字符串长度(count+str.length())<=(value*2+2)则按value*2+2长度扩容,而且
value=value*2+2,若(count+str.length())>(value*2+2),则按count+str.length()长度扩容,而且
value=count+str.length()。下次超出时再按以上方法与value*2+2比较扩容。
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
3.2 StringBuilder sbu=new StringBuilder();
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
public StringBuilder() {
super(16);
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
小结:
1.StringBuilder是jdk1.5引进的,而StringBuffer在1.0就有了;
2.StringBuilder和StringBuffer都是可变的字符串。可以经过append或者insert等方法改动串的内容;
3.StringBuffer是线程安全的而StringBuilder不是,于是在多线程的环境下优先使用StringBuffer,而其它状况下推荐使用
StringBuilder,因为它更快。
4.StringBuilder和StringBuffer都继承自AbstractStringBuilder类,AbStractStringBuilder主要实现了扩容、append、
insert方法。StrngBuilder和StringBuffer的相关方法都直接调用的父类。
5.StringBuilder和StringBuffer的初始容量都是16,程序猿尽可能手动设置初始值。以免屡次扩容所带来的性能问题;
6.StringBuilder和StringBuffer的扩容机制是这种:首先试着将当前数组容量扩充为原数组容量的2倍加上2,假设这个新容
量仍然小于预约的最小值(minimumCapacity),那么就将新容量定为(minimumCapacity),最后推断是否溢出,若溢出,
则将容量定为整型的最大值0x7fffffff。