走进java_了解ArrayList和LinkedList

OOP中,通常程序在运行的时候才知道创建多少对象,在此之前java中用数组解决了这个问题,可是随着以后的发展人们意识到数组在一定程度上具有局限性,必须是固定长度,和相同的数据类型,已经满足不了人们的需求,最终java提供了强大的容器解决了这个问题。容器(Collection)表示一组对象,它是集中收集的意思,就是吧一些数据收集起来。存放在collection库当中的数据,称为元素。

 

Java中容器主要是为了保存对象:可以分为CollectionMap

Collection 中定义了存取对象的一些方法 有细分为 SetListset中存放对象是无序不能重复, 而list是有序可重复。

Map接口的类用来存储键(key-值 (value)对 。

List:  List中元素必须有特定的顺序,ListCollection中添加了很多的方法,List中直接可以插入删除元素(对象)ArrayListLinkList都实现了List接口。

ArrayList:

它的jdk源码:private transient Object[]elementData;

可以看出它的底层是由数组来实现的,再看看它常用的一些方法。

public int size()                                                         

public boolean isEmpty()

public boolean contains(Objecto) 

public int indexOf(Objecto)

public Object[] toArray()

public E get(int index)

public E get(int index)

public Eset(int index, E element)

public boolean add(Ee)

public void add(int index, E element)

public E remove(int index)

 

其中get( ), set( ),add( ), remove( ) 方法比较重要,分析分析它的jdk源码

1,Get()  

 

// Returns the element at the specified position in this list.

public E get(int index) {
        rangeCheck(index);    //检查索引是否越界

        return elementData(index);
}


从中可以看出返回这个元素在list的确切位置,实际就是根据数组的下标得到这个数组下标所对应的元素。

 

2,ser( )

// Replaces the element at the specified position in this list with

  the specified element.

public E set(int index, E element) {

        rangeCheck(index);

 

        E oldValue = elementData(index);

        elementData[index] = element;

        return oldValue;

}

找到索引的确切位置,用新元素替换原来的元素,返回原来的元素。


3,add( )

// Inserts the specified element at the specified position in this

  list. Shifts the element currently at that position (if any) and

  any subsequent elements to the right (adds one to their indices)

 

public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,size - index);                      
        elementData[index] = element;
        size++;
}

往索引位置插入一个元素,size+1,但从索引位置开始向后每个元素都向右移动一位。

4remove()

// Removes the element at the specified position in this list.

public E remove(int index) {
        rangeCheck(index);

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

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

根据索引移除该索引位置上的元素,但从jdk源码来看,操作稍有些麻烦,每移除一个元素,从该元素开始到最后的元素都需要向左移动一位,需要注意的是移除不是删除,只是从容器中移走。

总结:

ArrayList:的底层使用数组来实现,效率比较高,查询,修改速度很快,但是插入,删除操作比较慢、效率低,线程不安全。


LinkedList:

再看看LinkedList, 继续看看源码

/**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node<E> first;

    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node<E> last;
从这里我们可以很清晰的看出它的底层实现和ArrayList有很大的区别,它的底层实现是用链表来实现的,一个first指针和last指针。 LinkedList的基本方法和ArrayList大致相同,增删改查稍有不同,重点在比较比较这些方法。

查找某个对象:

  public int indexOf(Object o) {
        int index = 0;
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null)
                    return index;
                index++;
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item))
                    return index;
                index++;
            }
        }
        return -1;
    }
从中可以看出,每查找某个对象,都要从头到尾把所有元素遍历一遍,因此查询效率较低,速度慢。

LinkedList中元素的添加和删除的底层实现和数据结构中双向链表结点的增加和删除操作原理是一样的。链表在结点的插入和删除方面要比数组方便的多,但是查询效率较低。

再来看看LinkedList中实际的一些方法:

LinkedList list=new LinkedList();
            list.add("张三");
	    list.add(new Date());
	    list.add(2, "xx");    //往指定的位置插入元素
	    list.addFirst(123);  //往首位插入元素  (123会被自动装箱)
	    list.addLast(456);   //往末尾插入元素  
	    list.remove(2);      // 移除第2个元素  (从0 开始..)
	    list.remove("456");    //移除特定的对象
	    System.out.println(list.getFirst()); //显示首个元素
	    System.out.println(list.getLast());  //显示最后一个元素
	    System.out.println(list.get(2));      // 通过索引值得到元素
	    System.out.println(list.indexOf(123));  //返回链表中对象的索引
显示结果:
123
456
xx
0

总结:

1,ArrayList的底层是用数组实现的,LinkedList的底层是用链表实现的。

2,在插入删除方面,ArrayList在中间插入一个元素,要导致从插入位置到最后一位元素都要向右移动一位,ListedList的开销是固定的。

3,对于随机查询而言,ArrayList效率要高,因为LinkedList要移动指针去查找。

4,ArrayList的容量大于初始容量是要进行扩容,而LinkedList则不用。

当然ArrayList和LinkedList各自有优缺点,那个好要根据实际情况而定。


这是我对ArrayList和LinkedList简单的理解,有什么不对的地方欢迎大家指出。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1.底层数据结构不同:ArrayList底层是数组,LinkedList底层是双向链表。 2.ArrayList的查询效率高,LinkedList的插入删除效率高。ArrayList的查询效率因为底层数组是连续的内存空间,所以可以直接根据索引定位到元素,时间复杂度为O(1),但是插入删除的效率因为需要移动元素,所以时间复杂度为O(n);LinkedList的插入删除效率高,因为只需要修改相邻元素的指针,时间复杂度为O(1),但是查询效率因为需要遍历整个链表,时间复杂度为O(n)。 3.ArrayList的内存空间使用效率高,LinkedList的内存空间使用效率低。ArrayList底层数组是连续的内存空间,可以预先分配一定的空间,避免频繁的扩容,所以内存空间使用效率高;LinkedList因为每个节点都需要保存前后指针,所以内存空间使用效率低。 4.ArrayList的线程不安全,LinkedList的线程不安全。因为ArrayListLinkedList都不是线程安全的,所以在多线程环境下需要注意线程安全问题。 5.ArrayList的迭代器效率高,LinkedList的迭代器效率低。ArrayList的迭代器效率高,因为底层数组是连续的内存空间,所以可以直接通过索引取元素,时间复杂度为O(1);LinkedList的迭代器效率低,因为需要遍历整个链表,时间复杂度为O(n)。 6.ArrayList的随机访问效率高,LinkedList的顺序访问效率高。因为ArrayList底层是数组,可以通过索引直接访问元素,所以随机访问效率高;LinkedList因为是链表,只能顺序访问,所以顺序访问效率高。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值