JAVA笔记(十八):集合、Collection、List、ArrayList、Vector、LinkedList

集合

一、集合的理解和好处

1、数组

(1)长度开始时必须指定,而且一旦指定,不能更改;

(2)保存的必须为同一类型的元素;

(3)使用数组进行增加/删除元素的代码比较麻烦。

2、集合

(1)可以动态保存任意多个对象,使用比较方便;

(2)提供了一系列方便的操作对象的方法:add,remove,set,get等;

(3)使用集合添加,删除新元素代码简洁

二、集合框架体系⭐⭐⭐⭐⭐

Java的集合类很多,主要分为两大类:

(1)集合主要是两组(单列集合 , 双列集合)

(2)Collection 接口有两个重要的子接口 List Set , 他们的实现子类都是单列集合

(3)Map 接口的实现子类 是双列集合,存放的 K-V(key-value键值对);

(4)两张图,背!!!!!

1、【单列集合Collection】

在这里插入图片描述

2、【双列集合Map】

在这里插入图片描述

三、Collection

1、Collection接口实现类的特点

   public interface Collection<E> extends Iterable<E>

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

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

(3)有些Collection的实现类,有些是有序的(List),有些不是有序(Set);

  • 有序:存放顺序和add顺序一样

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

2、Collection接口常用方法(ArrayList示例)

  1. add //添加单个元素
List list = new ArrayList();//接口可以指向实现该接口的类

list.add("lll");
list.add(1);//有自动装箱的过程 list.add(new Integer(1));
list.add(true);//有自动装箱的过程
System.out.println(list);//list里的元素都是对象
  1. remove 删除指定元素
list.remove("111");//指定删除某个元素
list.remove(0);//按下标删除第一个元素
  1. contains查找元素是否存在
System.out.println(list.contains("111"));
//有返回true,无返回false
  1. size获取元素个数
System.out.println(list.size());
  1. isEmpty判断是否为空
System.out.println(list.isEmpty());
  1. clear 清空
list.clear();
System.out.println("list=" + list); //list=[]
  1. addAll 添加多个元素(添加一个集合类)
ArrayList list1 = new ArrayList();
list1.add("haha");
list1.add("3213");
list.addAll(list1);
System.out.println(list);
  1. containsAll 查找多个元素是否存在
System.out.println(list.containsAll(list1));//都存在返回true
  1. removeAll 删除多个元素
list.removeAll(list1);

3、Collection遍历方式

1)使用Iterator(迭代器)

① Iterator对象称为迭代器,主要用于遍历Collection集合中的元素;

② 所有实现了Collection接口的集合类都有一个iterator()方法,用于返回一个实现了Iterator接口的对象,即可以返回一个迭代器;

③ Iterator 的结构:
在这里插入图片描述
在这里插入图片描述

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

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Collection col = new ArrayList();

        col.add(new Book("三国演义", "罗贯中", 10.1));
        col.add(new Book("小李飞刀", "古龙", 5.1));
        col.add(new Book("红楼梦", "曹雪芹", 34.6));


        //1. 先得到 col 对应的 迭代器
        Iterator iterator = col.iterator();

        //2. 使用while循环遍历
        //一个快捷键,快速生成 while iterator => itit
        while (iterator.hasNext()) {//判断是否还有数据
            //返回下一个元素,类型是Object
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }

        //3. 当退出while循环后 , 这时iterator迭代器,指向最后的元素
        //   此时iterator.next();  ===>抛出异常  NoSuchElementException
        
        //4. 如果希望再次遍历,需要重置我们的迭代器
        iterator = col.iterator();
        System.out.println("===第二次遍历===");
        while (iterator.hasNext()) {
            Object obj = iterator.next();
            System.out.println("obj=" + obj);
        }
    }
}

class Book {
    private String name;
    private String author;
    private double price;

    public Book(String name, String author, double price) {
        this.name = name;
        this.author = author;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

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

2)使用增强for循环

增强for循环,可以代替iterator迭代器。

特点:增强for就是简化版的iterator,本质一样。只能用于遍历集合或数组。

   基本语法:

   for(元素类型(先使用object) 元素名 :集合名或数组名){

                   访问元素

   }
public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Collection col = new ArrayList();

        col.add(new Book("三国演义", "罗贯中", 10.1));
        col.add(new Book("小李飞刀", "古龙", 5.1));
        col.add(new Book("红楼梦", "曹雪芹", 34.6));

        //使用增强for
        //快捷键:I
        for(Object book : col){ //动态绑定
            System.out.println("book=" + book); //book运行类型Book,调用的Book的tostring
        }
        //增强for用在数组上
        int[] nums = {1,4,3,7};
        for (int i : nums) {
            System.out.println(i);
        }
    }
}

4、Collection接口练习

在这里插入图片描述

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog("小白",2));
        arrayList.add(new Dog("小黑",1));
        arrayList.add(new Dog("小美",1));

        //迭代器循环
        System.out.println("=======迭代器======");
        Iterator iterator = arrayList.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //增强for循环
        System.out.println("=======增强for======");
        for (Object obj : arrayList) {
            System.out.println(obj);
        }
    }
}

class Dog {
    private String name;
    private int age;

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

四、List

1、List基本介绍

下面是对 Collection 的细化
前面 Collection 的方法,是 List 和 Set 接口都有的
现在讲只针对 List 的方法

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

List list = new ArrayList();
list.add("jack");
list.add("tom");
list.add("mary");
list.add("hsp");
list.add("tom");
System.out.println("list=" + list); //list=[jack, tom, mary, hsp, tom]

② List集合中的每个元素都有其对应的顺序索引(即对于List容器中的每个元素,都有一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素)即支持索引;

System.out.println(list.get(3));//hsp

③ List接口的实现类不止有ArrayList、LinkedList、Vector,还有很多

2、List常用方法

  1. add 插入元素
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
//在index = 1的位置插入一个对象
list.add(1, "林黛玉");
System.out.println("list=" + list); //list=[张三丰, 林黛玉, 贾宝玉]
  1. addAll 插入多个元素
List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1, list2); //在index = 1的位置插入多个对象
System.out.println("list=" + list); //list=[张三丰, jack, tom, 林黛玉, 贾宝玉]
  1. get 获取指定index位置的元素
System.out.println(list.indexOf("tom"));//2
  1. indexOf 返回obj在集合中首次出现的位置

  2. lastIndexOf 返回obj在集合中最后出现的位置

list.add("林黛玉");
System.out.println("list=" + list); //list=[张三丰, jack, tom, 林黛玉, 贾宝玉, 林黛玉]
System.out.println(list.lastIndexOf("林黛玉")); //5
  1. remove 移除指定index位置的元素,并返回此元素
Object obj = list.remove(0);
System.out.println(obj); //张三丰
System.out.println("list=" + list); //list=[jack, tom, 林黛玉, 贾宝玉]
  1. set 替换元素
list.set(1, "玛丽");  //1位置替换为玛丽
System.out.println("list=" + list); //list=list=[jack, 玛丽, 林黛玉, 贾宝玉, 林黛玉]
  1. subList 取子集合
List returnlist = list.subList(0, 2); //取下标为[0,2)的对象集合
System.out.println("returnlist=" + returnlist); //returnlist=[jack, 玛丽]

3、List的三种遍历方式

在这里插入图片描述

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //List 接口的实现子类 Vector LinkedList ArrayList(效果一样)
        //List list = new ArrayList();
        //List list = new Vector();
        List list = new LinkedList();

        list.add("jack");
        list.add("tom");
        list.add("鱼香肉丝");
        list.add("北京烤鸭子");

        //1. iterator
        System.out.println("=======iterator=======");
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }

        //2. 增强for
        System.out.println("=======增强for=======");
        for (Object o : list) {
            System.out.println(o);
        }

        //3. 普通for
        System.out.println("=======普通for=======");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}

练习
在这里插入图片描述


public class ListExercise02 {
 
    public static void main(String[] args) {
 
        //List list = new ArrayList();
        List list = new LinkedList();
        //List list = new Vector();
        list.add(new Book("红楼梦", "曹雪芹", 100));
        list.add(new Book("西游记", "吴承恩", 10));
        list.add(new Book("水浒传", "施耐庵", 19));
        list.add(new Book("三国", "罗贯中", 80));
        //list.add(new Book("西游记", "吴承恩", 10));
 
        //如何对集合进行排序
 
 
        //遍历
 
        for (Object o : list) {
            System.out.println(o);
        }
 
        //冒泡排序,调用静态方法
        sort(list);
 
        System.out.println("==排序后==");
 
        for (Object o : list) {
            System.out.println(o);
        }
 
    }
 
    public static void sort(List list) {
        int listSize = list.size();
        for (int i = 0; i < listSize - 1; i++) {
            for (int j = 0; j < listSize - 1 - i; j++) {
                //取出对象Book
                Book book1 = (Book) list.get(j);//向下转型
                Book book2 = (Book) list.get(j + 1);
                if (book1.getPrice() > book2.getPrice()) {//交换
                    list.set(j, book2);
                    list.set(j + 1, book1);
                }
            }
        }
    }
}

五、ArrayList

1、ArrayList基本介绍

(1)permits all elements,including null,ArrayList可以加入null,并且可以有多个;

ArrayList arrayList = new ArrayList();
arrayList.add(null);
arrayList.add("jack");
arrayList.add(null);
System.out.println(arrayList); //[null, jack, null]

(2)ArrayList 是由数组来实现数据存储的;

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

2、ArrayList底层结构和源码分析⭐⭐⭐⭐⭐

① ArrayList中维护了一个object类型的数组elementData,用于存放对象;

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

② 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第一次田间,则扩容elementData为10,如果需要再次扩容,则扩容elementData为1.5倍;(0->10->15->22…)
在这里插入图片描述

③ 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。

假设初始指定为 8
那么数组容量:8-->12-->18-->27...

1)【无参构造器】源码分析

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //解读源码
        //使用无参构造器创建ArrayList对象
        ArrayList list = new ArrayList(); //这里下断点
        //ArrayList list = new ArrayList(8);
        //使用for给list集合添加 1-10数据
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        //使用for给list集合添加 11-15数据
        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);

    }
}

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


2)【有参构造器】流程图


@SuppressWarnings({"all"})
public class ArrayListSource {
    public static void main(String[] args) {
        //解读源码
        //使用无参构造器创建ArrayList对象
        //ArrayList list = new ArrayList();
        ArrayList list = new ArrayList(8); //这里下断点
        //使用for给list集合添加 1-10数据
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        //使用for给list集合添加 11-15数据
        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
 
    }
}

在这里插入图片描述
后面的源码和无参的add()方法一样,只是因为第一次需要进行扩容时,就成功扩容(1.5倍扩容后就满足了需要的大小)

所以是直接在原来的基础上扩容1.5倍,而不是先初始化为10(初始化为10,是因为最开始0按照1.5倍扩容也还是0)
在这里插入图片描述
在这里插入图片描述

六、Vector

1、Vector基本介绍

① 定义说明;
在这里插入图片描述

② Vector底层是一个对象数组,protected Object[] elementData;

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

④ 开发中,需要线程同步安全时,考虑使用Vector。

2、Vector 和 ArrayList 的比较

在这里插入图片描述

(3)Vector的底层扩容结构

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //无参构造器
        //Vector vector = new Vector();
        //有参数的构造
        Vector vector = new Vector(8);//这里下断点
        for (int i = 0; i < 10; i++) {
            vector.add(i);
        }
        vector.add(100);
        System.out.println("vector=" + vector);
    }
}

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

七、LinkedList

1、LinkedList基本介绍

  1. LinkedList底层实现了双向链表和双端队列的特点;

  2. 可以添加任意元素(元素可以重复),包括null;

  3. 线程不安全,没有实现同步

2、LinkedList的底层操作机制

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

  2. LinkedList中维护了两个属性firstlast 分别指向首节点尾节点

  3. 每个节点(Node对象),里面又维护了prevnextitem三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表
    在这里插入图片描述

  4. 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率比较高;

  5. 模拟一个简单的双向链表。

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node mark = new Node("mark");

        //连接三个节点,形成双向链表
        jack.next = tom;
        tom.next = mark;
        mark.pre = tom;
        tom.pre = jack;

        //头尾结点
        Node first = jack;
        Node last = mark;

        //从头到尾遍历
        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.next;
        }

        //添加对象
        //1. 先创建一个新结点
        //2. 改变插入位置相邻两个元素的指向
        Node smith = new Node("Smith");
        smith.next = mark;
        smith.pre = tom;
        mark.pre = smith;
        tom.next = smith;

        //删除对象
        //改变删除对象相邻两个对象的指向
        jack.next = jack.next.next;
        jack.next.pre = jack;
        //从头到尾遍历
        System.out.println("=====从头到尾遍历=====");
        while(true){
            if(first == null){
                break;
            }
            System.out.println(first);
            first = first.next;
        }
    }
}

class Node {
    public Object item;
    public Node next;
    public Node pre;
    public Node(Object name) {
        this.item = name;
    }
    public String toString() {
        return "Node name = " + item;
    }
}

3、LinkedList底层结构

public class Test {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList(); //这里下断点
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        System.out.println("linkedList=" + linkedList); //linkedList=[1, 2, 3]

        //演示一个删除结点的
        linkedList.remove(); // 这里默认删除的是第一个结点
        //linkedList.remove(2);
        System.out.println("linkedList=" + linkedList); //linkedList=[2, 3]

        //修改某个结点对象
        linkedList.set(1, 999);
        System.out.println("linkedList=" + linkedList); //linkedList=[2, 999]

        //得到某个结点对象
        //get(1) 是得到双向链表的第二个对象
        Object o = linkedList.get(1);
        System.out.println(o);//999

        //因为LinkedList 是 实现了List接口, 遍历方式
        System.out.println("===LinkeList遍历迭代器====");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        System.out.println("===LinkeList遍历增强for====");
        for (Object o1 : linkedList) {
            System.out.println(o1);
        }
        System.out.println("===LinkeList遍历普通for====");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
    }
}

1)添加结点分析

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


2)删除结点分析

在这里插入图片描述

4、ArrayList和LinkedList比较

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

① 如果我们改查的操作多,选择ArrayList;

② 如果我们增删的操作多,选择ListedList;

③ 一般来说,在程序中,80-90%都是查询,大部分情况下会选择ArrayList;

④ 在项目中,会根据业务灵活选择,可能一个模块用ArrayList,另一个模块用ListedList;

⑤ ArrayList和LinkedList都是线程不安全的,需要在单线程情况下使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值