Java集合——Collection接口以及ArrayList,Vector,LinkedList的源码剖析——最认真的图解——第一章

1:集合体系图

Collection:单列集合,该接口有两个重要的子接口List Set,他们的实现子类都是单列集合
在这里插入图片描述
Map:双列集合,Map接口的实现子类,存放K-V
在这里插入图片描述

2:Collection方法

2.1 Collection接口和常用方法

  • Collection接口实现类的特点
public interface Collection< E > extends Iterable < E >

1 ) collection实现子类可以存放多个元素, 每个元素可以是Object

2)有些Collection的实现类,可以存放重复的元素,有些不可以

3)有些Collection的实现类,有些是有序的(List), 有些不是有序(Set)
4) Collection接口没有直接的实现子类,是通过它的子接口Set和List来实现的

在这里插入图片描述

  • Collection接口常用方法,以实现子类ArrayList来演示。CollectionMethod.java
1) add:添加单个元素
2) remove:删除指定元素
3) contains:查找元素是否存在
4) size:获取元素个数
5) isEmpty:判断是否为空
6) clear:清空
7) addAll:添加多个元素
8) containsAll:查找多个元素是否都存在9) removeAll:删除多个元素
public class CollectionMethod {
    public static void main(String[] args) {
        List list=new ArrayList();
//        1) add:添加单个元素
        list.add("zlj");
        list.add(10);
        list.add(true);
//        2) remove:删除指定元素
        list.remove(1);
        System.out.println("list:"+list);
//        3) contains:查找元素是否存在
        System.out.println(list.contains(true));
//        4) size:获取元素个数
        System.out.println(list.size());
//        5) isEmpty:判断是否为空
        System.out.println(list.isEmpty());
//        6) clear:清空
        list.clear();
        System.out.println("list:"+list);
//        7) addAll:添加多个元素
        ArrayList list2=new ArrayList();
        list2.add("西游记");
        list2.add("水浒传");
        list.addAll(list2);
//        8) containsAll:查找多个元素是否都存在
        list.containsAll(list2);
//        9) removeAll:删除多个元素
        list.add("java虚拟机");
        list.removeAll(list2);
        System.out.println("list:"+list);
    }
    }

2.2 Collection接口遍历元素的方式

2.2.1 使用Iterator(迭代器)基本介绍

在这里插入图片描述

  1. Iterator对象称为迭代器,主要用于遍历Collection集合中的元素。2)所有实现了Collection接口的集合类都有一个iterator(0方法, 用以返回一个实现了Iterator接口的对象, 即可以返回一个迭代器。

  2. Iterator的结构
    在这里插入图片描述
    注意:在调用iterator.next()方法之前必须要调用iterator.hasNext()进行检测。若不调用,且下一条记录无效,直接调用iterator.next()会抛出NoSuchElementException异常。如果希望再次遍历,需要我们重置一个迭代器

  3. Iterator仅用于遍历集合, Iterator本身并不存放对象。

实例演示

public class CollectionIterator {
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add(new Book("java虚拟机","300"));
        list.add(new Book("java规范","100"));
        list.add(new Book("Spring","200"));
        //1:先得到list对于的迭代器
        Iterator iterator = list.iterator();
         //2:使用while循环遍历,判断是否还有数据
        while (iterator.hasNext()){
          //3:返回下一个元素
            System.out.println(iterator.next());
        }
    }
}
class Book{
    private String name;
    private String price;

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price='" + price + '\'' +
                '}';
    }
    public Book(String name, String price) {
        this.name = name;
        this.price = price;
    }

}

2.2.2 for循环增强

增强for循环(底层仍然是iterator迭代器),可以代替iterator迭代器,特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或数组。for循环增强也可以在数组中使用

基本语法
for(元素类型元素名:集合名或数组名){
访问元素
}

实例演示:如上代码的iterator改成for循环增强即可

//..
        for (Object book:list){
            System.out.println("book="+book);
        }
       //...
book=Book{name='java虚拟机', price='300'}
book=Book{name='java规范', price='100'}
book=Book{name='Spring', price='200'}

3:List接口和方法

3.1 List接口基本介绍

在这里插入图片描述
常用的有ArrayList,LinkedList,Vector

List接口是Collection接口的子接口

  1. List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复,

  2. List集合中的每个元素都有其对应的顺序索引,即支持索引。

  3. List容器中的元素都对应一 个整数型的序号记载其在容器中的位置, 可以根据序号存取容器中的元素。
    案例演示

public class ListMethod {
    public static void main(String[] args) {
// List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复,
        List list=new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        System.out.println("list="+list);
//List集合中的每个元素都有其对应的顺序索引,即支持索引。
        System.out.println(list.get(3));
    }
}
list=[1, 2, 3, 3]
3

3.2 List接口的常用方法

List集合里添加了一些根据索引来操作集合元素的方法

  1. void add(int index, Object ele):在index位置插入ele元素

  2. boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来

  3. Object get(int index):获取指定index位置的元素

  4. int indexOf(Object obj):返回obj在集合中首次出现的位置

  5. int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置

  6. Object remove(int index):移除指定index位置的元素,并返回此元素

  7. Object set(int index, Object ele):设置指定index位置的元素为ele ,相当于是替换.

  8. List subList(int fromIndex, int tolndex):返回从fromIndex到tolndex位置的子集合
    案例演示

public class ListMethod {
    public static void main(String[] args) {
// List集合类中元素有序(即添加顺序和取出顺序一致)、 且可重复,
        List list=new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        System.out.println("list="+list);
//List集合中的每个元素都有其对应的顺序索引,即支持索引。
        System.out.println(list.get(3));

//        1) void add(int index, Object ele):在index位置插入ele元素
        list.add(1,"java");
        System.out.println("list="+list);
//        2) boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        List list2= new ArrayList();
        list2.add("男");
        list2.add("女");
        list.addAll(1,list2);
        System.out.println("list="+list);

//        3) Object get(int index):获取指定index位置的元素
        System.out.println( list.get(1));
//
//        4) int indexOf(Object obj):返回obj在集合中首次出现的位置
        System.out.println(list.indexOf(3));

//        5) int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        System.out.println(list.lastIndexOf(3));

//        6) Object remove(int index):移除指定index位置的元素,并返回此元素
        list.remove(0);
        System.out.println("list="+list);
//        7) Object set(int index, Object ele):设置指定index位置的元素为ele ,相当于是替换.
        list.set(0,"man");
        System.out.println("list="+list);
//        8) List subList(int fromIndex, int tolndex):返回从fromIndex到tolndex位置的子集合
        System.out.println(list.subList(0,3));
    }
}

3.3 List接口的三种遍历方式

  1. 迭代器
  2. 增强for循环
  3. 使用普通for循环
    案例演示
public class ListFor {
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(3);
        //1.迭代器
        System.out.println("======迭代器=======");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(next);
        }
        System.out.println("======增强for循环=======");
        for (Object object:list){
            System.out.println(object);
        }
        System.out.println("======普通for循环=======");
        for (int i=0;i<list.size();i++){
            System.out.println(list.get(i));
        }
    }
}

4:ArrayList源码剖析

ArrayList的注意事项

  1. ArrayList可以加入null,并且加多个

  2. ArrayList是由数组来实现数据存储的

  3. ArrayList基本等同于Vector ,除了ArrayList是线程不安全(执行效率高)看源码,在多线程情况下,不建议使用ArrayList

ArrayList的底层操作机制源码分析(重点,难点)
先说结论在分析源码
1 ) ArrayList中维护了一个Object类型的数组elementData

 transient Object[] elementData//transient 表示短暂的,瞬间,表示该属性不会被序列化

2)当创建对象时,如果使用的是无参构造器,则初始elementData容量为0 (jdk7是10)
3)当添加元素时:先判断是否需要扩容,如果需要扩容,则调用grow方法,否则直接添加元素到合适位置

4)如果使用的是无参构造器,如果第一次添加,需要扩容的话,则扩容elementData为10,如果需要再次扩容的话,则扩容elementData为1.5倍。

5)如果使用的是指定容量capacity的构造器,则初始elementData容量为capacity

6)如果使用的是指定容量capacity的构造器,如果需要扩容,则直接扩容elementData为1.5倍。

当创建对象时,如果使用的是无参构造器案例演示

public class ArrayListSource {
    public static void main(String[] args) {
        //解读源码
        //使用无参构造器创建ArrayList对象
        ArrayList arrayList=new ArrayList();
        //使用for循环给list添加1-10数据
        for (int i=0;i<=10;i++){
            arrayList.add(i);
        }
        //使用for循环给list添加11-15数据
        for (int i=11;i<=15;i++){
            arrayList.add(i);
        }
        //使用for循环给list添加16,17,18数据
        arrayList.add(100);
        arrayList.add(200);
        arrayList.add(null);
    }
}

源码剖析
Debug
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当创建对象时,如果使用的是有参构造器案例演示
源码剖析
Debug
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

5:Vector源码剖析

Vector注意事项
1)Vector类的定义说明
在这里插入图片描述
2) Vector底层也是一个对象数组

protected Object[] elementData;

3 ) Vector是线程同步的,即线程安全,Vector类的操作方法带有synchronized

    public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);

        return elementData(index);
    }

4)在开发中需要线程同步安全时,需要考虑使用Vector
案例演示

public class VectorSource {
    public static void main(String[] args) {
        //无参构造器
        Vector<Object> objects = new Vector<>();
        for (int i=0;i<10;i++){
            objects.add(i);
        }
    }
}

源码剖析
Debug
在这里插入图片描述

6:LinkedList源码剖析

6.1 LinkedList的全面说明和底层操作机制

全面说明
1 ) LinkedList底层实现了双向链表和双端队列特点
2 )可以添加任意元素(元素可以重复),包括null
3 )线程不安全,没有实现同步

LinkedList的底层操作机制

1 ) LinkedList底层维护了一个双向链表.

2 ) LinkedList中维护了两个属性first和last分别指向首节点和尾节点

3)每个节点(Node对象) ,里面又维护了prev、next、 item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表.

4)所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高。
在这里插入图片描述
模拟双向链表遍历

public class LinkedListDemo {
    public static void main(String[] args) {
//模拟一个简单的双向链表
        Node zlj = new Node("zlj");
        Node zzg = new Node("zzg");
        Node lqx = new Node("lqx");
        //连接三个节点,形成双向链表
        //zlj->zzg->lqx
        zlj.next=zzg;
        zzg.next=lqx;
        //lqx->zzg->zlj
        lqx.pre=zzg;
        zzg.pre=zlj;
        Node first=zlj;//first引用指向zlj,就是双向链表的头节点
        Node last=lqx;//last引用指向lqx,就是双向链表的尾节点
        //从头到尾进行遍历
        System.out.println("============从头到尾进行遍历============");
        while (true){
            if (first==null) {
                break;
            }
           System.out.println(first);
            first=first.next;
        }
        //从尾到头进行遍历
        System.out.println("============从尾到头进行遍历==============");
        while (true){
            if (last==null){
                break;
            }
            System.out.println(last);
            last=last.pre;
        }

    }
}
//定义一个Node类,Node对象,表示双向链表的一个节点
class Node{
    public Object item;//真正存放数据
    public Node next;//指向后一个节点
    public Node pre;//指向前一个结点
    public Node(Object name){
        this.item=name;
    }
    @Override
    public String toString() {
        return "Node{" +
                "item=" + item +
                '}';
    }
}
============从头到尾进行遍历============
Node{item=zlj}
Node{item=zzg}
Node{item=lqx}
============从尾到头进行遍历==============
Node{item=lqx}
Node{item=zzg}
Node{item=zlj}

模拟双向链表的添加和删除(主要代码和上面一样)

//....
        //演示链表添加对象
        Node node = new Node("添加元素");
        zlj.next=node;
        node.next=zzg;
        zzg.pre=node;
        node.pre=zlj;
        //..

============从头到尾进行遍历============
Node{item=zlj}
Node{item=添加元素}
Node{item=zzg}
Node{item=lqx}
/...
        //演示链表添加对象
        Node node = new Node("添加元素");
        zlj.next=node;
        node.next=zzg;
        zzg.pre=node;
        node.pre=zlj;
        //演示链表删除对象
        zlj.next=zzg;
        zzg.pre=zlj;
        //..
============从头到尾进行遍历============
Node{item=zlj}
Node{item=zzg}
Node{item=lqx}

6.2 LinkedList源码剖析

linkedList 的add方法源码剖析

public class LinkedListCRUDSource {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        System.out.println("linkedList="+linkedList);
    }
}

在这里插入图片描述

7:List实现类的选择

在这里插入图片描述
在这里插入图片描述
如何选择ArrayList和LinkedList:

1)如果我们改查的操作多,选择ArrayList

2)如果我们增删的操作多,选择LinkedList

3)一般来说,在程序中,80%-90%都是查询,因此大部分情况下会选择ArrayList
4)在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块是LinkedList.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值