Vector和ArrayList的故事

1 首先讲讲Vector

在Java2之前,要存储多个数据,是存储在Vector类中的。

通过读源代码发现Vector类的底层其实是一个Object数组,另外重要的是Vector类中的方法是同步的(synchronized)。

protected Object[] elementData;

public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
}

public Vector(int initialCapacity) {
        this(initialCapacity, 0);
}

存储原理:
1.表面上把数据存储到Vector中,其实底层依然是把数据存储到Object数组中的。
2.我们发现该数组的元素类型是Object类型,意味着其中能存储任意类型的对象。
注:集合中只能存储对象,不能存储基本数据类型的值

在Java5之前,必须对基本数据类型手动装箱。
如:v.addElement(Integer.valusOf(123));
从Java5开始,支持自动装箱操作
如:v.addElement(123);
其底层依然是手动装箱。

3.集合类中存储的对象,都存储对象的引用,而不是对象本身。

呃,Vector里的方法就不提了,那是API要讲的东西。

2 下面说说ArrayList

ArrayList类是Java集合框架出现之后用来取代Vector类的(since 1.2)
二者底层原理都是基于数组的算法,一模一样。

3 区别

3.1 容量上的区别

3.1.1 Vector

初始化

Vector初始化的时候,会默认开一个大小为10的空间。

/**
* Constructs an empty vector so that its internal data array
* has size {@code 10} and its standard capacity increment is
* zero.
*/
public Vector() {
        this(10);
}

public Vector(int initialCapacity) {
        this(initialCapacity, 0);
}

扩容

private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
}

capacityIncrement参数可以在初始化时指定,未指定时默认是0,如果未指定capacityIncrement,则以2 * oldCapacity扩容。

3.1.2 ArrayList

初始化

在Java7之前,即使使用new ArrayList创建对象,一个元素都不存储,但是在堆空间依然初始化了容量为10的Object数组(size还是0)。

public ArrayList() {
        this(10);
}

而Java7之后的代码:
ArrayList构造一个默认初始容量为10的空列表。

1.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; size = 0;
2.当向数组中添加第一个元素时,通过add(E e)方法中调用的ensureCapacityInternal(size + 1)方法,即ensureCapacityInternal(1)
3.在ensureCapacityInternal(int minCapacity)方法中,可得的minCapacity=DEFAULT_CAPACITY=10,然后再调用ensureExplicitCapacity(minCapacity)方法,即ensureExplicitCapacity(10)
4.在ensureExplicitCapacity(minCapacity)方法中调用grow(minCapacity)方法,即grow(10),此处为真正具体的数组扩容的算法,在此方法中,通过elementData = Arrays.copyOf(elementData, 10)具体实现了elementData数组初始容量为10的构造。

摘自:http://blog.csdn.net/jdsjlzx/article/details/52675726
简单讲就是:
Java7开始,new ArrayList()之后,底层创建了一个空数组,然后在第一次调用add方法的时候,才重新去初始化数组,容量设置为10.

扩容

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

newCapacity = oldCapacity + (oldCapacity >> 1);等价于newCapacity = oldCapacity + (oldCapacity / 2);也就是1.5 * oldCapacity扩容

3.2 并发上的区别

Vector:所有的方法都使用了synchronized修饰符。线程安全但是性能较低。适用于多线程环境。
ArrayList:所有的方法都没有使用synchronized修饰符。线程不安全但是性能较高。

但,即使以后在多线程环境下,我们也不使用Vector类。
推荐使用下面的:

ArrayList list = Collections.synchronizedList( new ArrayList() );

源代码我就不放了,在同步的实现上和Vector的区别就是:
Vector是使用同步方法实现,synchronizedList使用的是同步代码块实现。

分析:
1.我们都知道加同步锁会一定程度上影响性能,而加锁的范围与性能成反比。
2.同步代码块比同步方法加锁更加灵活(范围可自定义)
3.同步代码块可以选择对哪个对象加锁,而同步方法只能给this对象加锁。

所以说二者比较起来,synchronizedList更加灵活,因为可以指定加锁的对象

但是需要注意一下:
synchronizedList中并没有 使用synchronized代码块。

所以在遍历的时候,要手动进行同步处理,另外其自身具备的方法可以同步,其自身不具备的方法,需要手动同步。例如:

@NotThreadSafe  
class BadListHelper <E> {  
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());  
  
    public synchronized boolean putIfAbsent(E x) {  
        boolean absent = !list.contains(x);  
        if (absent)  
            list.add(x);  
        return absent;  
    }  
} 
@ThreadSafe  
class GoodListHelper <E> {  
    public List<E> list = Collections.synchronizedList(new ArrayList<E>());  
  
    public boolean putIfAbsent(E x) {  
        synchronized (list) {  //获得list锁对象,其他线程将不能获得list锁来来改变list对象。  
            boolean absent = !list.contains(x);  
            if (absent)  
                list.add(x);  
            return absent;  
        }  
    }  
}  

摘自:http://blog.csdn.net/baidu_37464759/article/details/77683588

上面的代码A线程执行完boolean absent = !list.contains(x);后,B线程获得list对象的锁,如果对list的值进行修改,接着A线程再向后执行,就会造成java.util.ConcurrentModificationException异常。
上面的代码是对this加锁,下面的代码是对list加锁,要注意同步锁对象的选择是否正确。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容