A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

集合框架中ArrayList底层是数组结构为什么能存不同对象?数组不是只能存同一类的对象吗?底层是怎么实现的?

3 个回复

倒序浏览
本帖最后由 赵云柯 于 2012-8-29 15:53 编辑

查一下源码就明白了

ArrayList的空参数构造函数是这样定义的:

public ArrayList() {
        this(10);//这里调用的是另一个构造函数,public ArrayList(int initialCapacity)
}


public ArrayList(int initialCapacity)的源码如下:

public ArrayList(int initialCapacity) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];//构造函数根据参数创建指定大小的Object类型数组,并赋值给elementData 。elementData 是ArrayList类的Object[]类型私有成员变量
}


所以,创建一个 ArrayList类型的对象时,底层实际上是创建了一个Object[]类型的对象。而Object是所有类型的父类,所以ArrayList能存不同类型的对象。

评分

参与人数 1技术分 +1 收起 理由
张_涛 + 1 赞一个!

查看全部评分

回复 使用道具 举报
老师的详细分析 可以帮助楼主

ArrayList是List接口的可变数组的实现。实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。   每个ArrayList实例都有一个容量,该容量是指用来存储列表元素的数组的大小。它总是至少等于列表的大小。随着向ArrayList中不断添加元 素,其容量也自动增长。自动增长会带来数据向新数组的重新拷贝,因此,如果可预知数据量的多少,可在构造ArrayList时指定其容量。在添加大量元素 前,应用程序也可以使用ensureCapacity操作来增加ArrayList实例的容量,这可以减少递增式再分配的数量。
   注意,此实现不是同步的。如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步。
1.构造函数

public ArrayList() {
    this(10);
}

public ArrayList(int initialCapacity) {
    super();//默认可以不写
        if (initialCapacity < 0)//初始化的容量如果小于0就抛出异常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);

    //创建一个大小为10的Object数据对象     this.elementData = new Object[initialCapacity];

}



2. add函数

/**
     * Appends the specified element to the end of this list.//在列表的后面加上元素
     *
     * @param e element to be appended to this list
     * @return <tt>true</tt> (as specified by {@link Collection#add})
     */
public boolean add(E e) {
    ensureCapacity(size + 1);  // Increments modCount!!
    elementData[size++] = e;//将元素加到数组里面     return true;
}

//minCapacity

public void ensureCapacity(int minCapacity) {
    modCount++;
    int oldCapacity = elementData.length;
    if (minCapacity > oldCapacity) {//如果超过范围
        Object oldData[] = elementData;
        int newCapacity = (oldCapacity * 3)/2 + 1;//增加容量为1.5倍加1
            if (newCapacity < minCapacity)
        newCapacity = minCapacity;
            // minCapacity is usually close to size, so this is a win:
            elementData = Arrays.copyOf(elementData, newCapacity);//把老的数组copy到新的数组中去     }
}



3 get函数的方法

/**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
public E get(int index) {
    RangeCheck(index);//判断数组下标是否越界
    return (E) elementData[index];//通过下标得到元素然后返回
}

private void RangeCheck(int index) {
    if (index >= size)//如果越界就抛出异常
        throw new IndexOutOfBoundsException(
        "Index: "+index+", Size: "+size);
}



4.remove的函数

/**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
public E remove(int index) {
    RangeCheck(index);

    modCount++;
    E oldValue = (E) elementData[index];

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,//自己copy给自己,就是移位
                 numMoved);
    elementData[--size] = null; // Let gc do its work

    return oldValue;
}



评分

参与人数 2技术分 +1 黑马币 +6 收起 理由
张_涛 + 1 赞一个!
唐见 + 6 很给力!

查看全部评分

回复 使用道具 举报
ArrayList是集合,集合本来就是存放对象,不用考虑类型。

正是因为这样子(存入对象类型不一定相同),编译时没错,但运行阶段会暴露错误。

所有才有了泛型限定存入集合中的元素为指定泛型类型。

这也是泛型只在编译阶段起作用,运行时去掉了泛型的原因。

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马