Collection集合继承结构

252 阅读21分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情

🏀集合概述

❤️首先我们要先明确一下,什么是集合?有什么用?

    ⭐️数组其实就是一个集合;集合实际上就是一个容器;可以来容纳其它类型的数据。

    ⭐️为什么说集合在开发中使用较多?
集合是一个容器,是一个载体,可以一次容纳多个对象。在实际开发中;假设连接数据库,数据库当中有10条记录,那么假设把这10条记录查询出来,在java程序中会将10条数据封装成10个java对象,然后将10个java对象放到某一个集合当中,将集合传到前端,然后遍历集合,将一个数据一个数据展现出来。

❤️集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。集合中存储的是引用
❤️注意:集合在java中本身是一个容器,是一个对象。集合中任何时候存储的都是“引用”

    ⭐️当然也可以把多个集合放到一个集合里;通俗来讲:我们用一个袋子装苹果,一个袋子装梨子;那么我们就可以找一个大袋子把这两个小袋子装入其中!

❤️在java中每一个不同的集合,底层会对应不同的数据结构。 往不同的集合中存储元素,等于将数据放到了不同的数据结构当中。不同的数据结构,数据存储方式不同:

    ⭐️例如:数组、二叉树、链表、哈希表...

        (1)集合c1中放数据,可能是放到数组上了。
(2)集合c2中放数据,可能是放到二叉树上了。
.....
⭐️使用不同的集合等同于使用了不同的数据结构!

     ⭐️java中已经将数据结构实现了,已经写好了这些常用的集合类,我们只需要掌握怎么用?在什么情况下选择哪一种合适的集合去使用即可。

     例如:

        (1)new ArrayList(); 创建一个集合对象,底层是数组。
(2)new LinkedList(); 创建一个集合对象,底层是链表。
(3)new TreeSet(); 创建一个集合对象,底层是二叉树。
.....

❤️集合在java JDK中哪个包下?
⭐️java.util.*;所有的集合类和集合接口都在java.util包下

❤️在java中集合分为两大类
⭐️一类是单个方式存储元素:
单个方式存储元素,这一类集合中超级父接口:java.util.Collection;

     ⭐️ 一类是以键值对儿的方式存储元素
以键值对的方式存储元素,这一类集合中超级父接口:java.util.Map;

❤️Collection集合继承结构图

❤️集合的内容很重要,为了掌握结合,建议大家自己动手画一下常用的的继承UML图

⭐️Collection集合继承结构图

❤️总结 

⭐️List集合存储元素的特点:

           有序可重复

           有序,存进去的顺序和取出来的顺序相同,每个元素有下标

           可重复:存进去1,还可以在存储1

(1)ArrayList: 底层是数组,是非线程安全的。

(2)LinkedList: 底层是双向链表。

(3)Vector: 底层也是数组,线程是安全的,效率比较低,使用较少。

⭐️Set(Map)集合存储元素的特点

          无序,不可重复

          无序,存进去的顺序和取出的顺序不一定相同,另外Set集合元素没有下标

          不可重复,存进去1,不能再次储存了

(1)HashSet: 底层是HashMap,放到HashSet集合中的元素等同于放到HashMap集合key部分了

(2)TreeSet: 底层是TreeMap,放到TreeSet集合中的元素等同于放在TreeMap集合key部分了。

(3)SorteSet (SorteMap) 集合存储元素特点

          首先是无序不可重复(因为继承Set集合),但是SoreSet集合中的元素是可以排序的

          可排序:可以按照大小顺序排序

(6)HashMap: 底层是哈希表。

(7)HashTable: 底层也是哈希表,只不过线程是安全的,效率较低使用较少。

(8)Prorerties:线程是安全的,并且key和value只能储存字符串String。

(9)TreeMap:底层是二叉树,TreeMap集合的key可以自动按照大小顺序排序。

🏀Collection集合

❤️Collection接口中常用的方法

❤️关于java.util.Collection接口中常用的方法:

⭐Collection集合中能存放什么元素?

(1)没有使用“泛型”之前,Collection中可以存储Object的所有子类型。

(2)使用了“泛型”之后,Collection中只能存储某个具体的类型。

(3)集合中不能直接存储基本数据类型,也不能存 java对象,只能存储java对象的内存地址

Collection中的常用方法

 (1)boolean add(Object e)   向集合中添加元素

 (2)int size()  获取集合中元素的个数

 (3)void clear()  清空集合

 (4)boolean contains(Object obj)  判断当前集合中是否包含元素obj

 (5)boolean remove(Object obj)  删除集合中的某个元素

 (6)boolean isEmpty()  判断该集合中元素的个数是否为0

 (7)Object[] toArray()  把集合转换成数组。【了解】

Collection中的常用方法


package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest01 {
    public static void main(String[] args) {
        // 1.创建一个集合对象
        // Collection c = new Collection(); //接口是抽象的,无法实例化

        //2.多态
        Collection c = new ArrayList();
        // 测试Collection接口中的常用方法:

        // 2.1 boolean add(Object obj) 向结合中添加元素
        c.add(100); // 自动装箱,实际上放进去了一个对象的内存地址。Integer x = new Integer(100)
        c.add(3.14); // 自动装箱,不能放基本数据类型,只能存储引用
        c.add(new Object());
        c.add(new Student());
        c.add(true); // 自动装箱

        // 2.2 int size() 获取集合中元素的个数
        System.out.println("集合中元素的个数是:"+c.size()); // 5

        // 2.3 void clear() 清空集合
        c.clear();
        System.out.println("集合中元素的个数是:"+c.size()); // 0

        // 再次重新向集合里面添加元素,虽然不是new的,但是有自动装箱机制,实际上存储的也是引用
        c.add("hello");
        c.add(100);
        c.add(3.14);
        c.add("蜘蛛侠");

        // 2.4 boolean contains(Object obj) p判断结合中是否包含当前对象
        System.out.println(c.contains("蜘蛛侠")); // true

        // 2.5 boolean remove()  删除集合中某个元素
        System.out.println("集合中元素的个数是:"+c.size()); // 4
        c.remove(100);
        System.out.println("集合中元素的个数是:"+c.size()); // 3

        //2.6  boolean isEmpty()  判断该集合中元素的个数是否为0
        System.out.println(c.isEmpty()); //集合不为空 false
        c.clear();
        System.out.println(c.isEmpty()); //集合为空 true

        //2.7 Object[] toArray() 把集合转换成数组(了解)
        c.add("abc");
        c.add("def");
        c.add("100");
        c.add(3.14);
        Object[] obj = c.toArray();
        for (int i = 0; i < obj.length; i++) {
            System.out.print(obj[i] +  " ");
        }


    }
}

class Student{

}

❤️Collection集合迭代(重要)

⭐Collection结合继承Iterable,里面有iterator方法,调用这个方法返回Iterator对象;Iterator是一个迭代器对象,通过调用里面的方法就可以完成迭代打印!

⭐迭代器对象Iterator中的两个方法:
(1)boolean hashNext()如果仍有元素可以迭代,则返回true
(2)Object next() 返回迭代的下一个元素

注意: 以下讲解的遍历方式/迭代方式,是所有Collection集合通用的一种方式。
Map集合中不能用;在所有的Collection以及子类中使用

package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

//集合迭代(遍历)专题
public class CollectionTest02 {
    public static void main(String[] args) {
        // 1.创建集合对象
        // 后面的集合无所谓,主要是看前面的Collection接口,怎么遍历/迭代。
        Collection c = new ArrayList();

        //1.1 添加元素
        c.add("abc");
        c.add("def");
        c.add(100);
        c.add(new Object());

        // 2.对集合Collection进行遍历/迭代
        // 2.1 第一步:获取集合对象的迭代器对象Iterator
        Iterator it = c.iterator();
        // 2.2 通过以上获取的迭代器对象开始迭代/遍历集合
        /*
            迭代器对象Iterator中的两个方法:
            (1)boolean hashNext()如果仍有元素可以迭代,则返回true
            (2)Object next() 返回迭代的下一个元素
        */

        // 利用迭代器对象Iterator中的方法取出数据
        /*boolean hasNext = it.hasNext();
        if(hasNext){
            //不管当初存进去什么,取出来的统一都是Object
            Object obj = it.next();
            System.out.println(obj); //取出abc
        }*/

        // 利用循环都取出来
        while(it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        }

    }
}

迭代器执行的原理

根据上面代码的理解,我们一起画出迭代器的执行原理吧!

❤️ArrayList集合和HashSet集合对比

(1)ArrayList集合有序可重复,怎么放进去就怎么取出来,并且元素是可以重复的!
(2)HashSet集合无序不可重复

          无序:存进去和取出的顺序不一定相同!

          不可重复:存储100,不能再存储100!

(3)it.next()取出来的还是Integer类型(存进去是什么类型取出来还是什么类型),打印的时候才会转换成字符串!

package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;

public class CollectionTest03 {
    public static void main(String[] args) {
        //1.创建集合对象
        Collection c1 = new ArrayList();
        //2.添加元素
        c1.add(1); //自动装箱,Integer x = new Integer(1)
        c1.add(2);
        c1.add(3);
        c1.add(4);
        c1.add(1);
        //3.迭代/遍历集合
        Iterator it = c1.iterator();
       /* while(it.hasNext()){
            System.out.println(it.next());
        }*/

        // 写成下面这种方式,来证实取出来的是Integer类型
        while(it.hasNext()){
            Object obj = it.next();
            if(obj instanceof Integer){ // 验证实际上取出来的还是Integer类型
                System.out.println(obj); // 1 2 3 4 1
            }
        }


        // HashSet集合:无序不可重复
        Collection c2 = new HashSet();
        // 无序:存进去和取出的顺序不一定相同。
        // 不可重复:存储100,不能再存储100;不会报错,只是不会再打印出来,
        c2.add(100);
        c2.add(200);
        c2.add(300);
        c2.add(90);
        c2.add(400);
        c2.add(50);
        c2.add(60);
        c2.add(100); //这个100不会被打印出来

        Iterator it2 = c2.iterator();
        while(it2.hasNext()){
            System.out.println(it2.next()); //400 50 100 200 90 300 60
        }

    }
}

❤️contains方法深入理解

(1)boolean contains(Object o),判断集合中是否包含某个对象o,如果包含返回true, 如果不包含返回false。

(2)contains方法是用来判断集合中是否包含某个元素的方法,那么它在底层是怎么判断集合中是否包含某个元素的呢?
⭐实际上contains方法调用了equals方法进行比对;equals方法返回true,就表示包含这个元素。

package com.bjpowernode.javase.collection;

import java.util.ArrayList;
import java.util.Collection;

public class CoolectionTest04 {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c = new ArrayList();

        // 向集合中存储元素
        String s1 = new String("abc");
        c.add(s1);
        String s2 = new String("def");
        c.add(s2);

        // 求集合元素的个数
        System.out.println("元素的个数:+"+c.size());

        // 新建一个String对象
        String x = new String("abc");

        // c集合是否包含x?结果是true还是false?
        // c集合不包含x,但是结果确实true,这是因为contains底层调用了equals方法
        // 所以对于自己定义的类型,一定要重写equals方法
        System.out.println(c.contains(x)); //true

    }
}

⭐内存图

 ⭐contains方法测试

⭐测试contains方法
结论: 存放在一个集合中的类型,一定要重写equals方法。

package com.bjpowernode.javase.collection;

import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest05 {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c = new ArrayList();
        // 创建用户对象
        User u1 = new User("jack");
        c.add(u1);
        User u2 = new User("jack");

        // 判断结合中是否包含u2?结果是true还是false?
        // 没有重写equals方法之前,比较的是内存地址,结果false
        System.out.println(c.contains(u2)); //false
        // 重写equals方法之后,比较的是内容
        System.out.println(c.contains(u2)); //true


        Integer x = new Integer(100);
        Integer y = new Integer(100);
        c.add(x);
        //true,Integer类里面的equals方法默认已经被重写了
        System.out.println(c.contains(y)); 
    }
}

// 创建一个类
class User{
    private String name;
    // 构造方法
    public User() {
    }
    public User(String name) {
        this.name = name;
    }

    // 重写equals方法
    public boolean equals(Object o) {
        if(o == null || !(o instanceof User)) return false;
        if(this == o) return true;
        User u  = (User)o;
        return u.name.equals(this.name);
    }


}

❤️remove方法深入理解

⭐存放在一个集合中的类型,调用remov方法,底层也会调用equals()方法,所以也一定要重写equals方法。

package com.bjpowernode.javase.collection;

import java.util.ArrayList;
import java.util.Collection;

//remove方法也调用了equals方法
public class CollectionTest06 {
    public static void main(String[] args) {
        // 创建集合对象
        Collection c = new ArrayList();
        // 创建字符串对象并加进去
        String s1 = new String("hello");
        c.add(s1);

        // 创建一个新的字符串对象,并移除
        // s1.equals(s2) java认为s1和s2是一样的。删除s2就是删除s1。
        String s2 = new String("hello");
        c.remove(s2);

        // 集合元素的个数
        System.out.println(c.size()); //0



    }
}

❤️集合和迭代器中的remove方法对比

(1)Iterator it = c.iterator();获取迭代器对象,迭代器用来遍历集合,
此时相当于对当前集合的状态拍一个快照,迭代器迭代的时候会参照这个快照进行迭代
(2)关于集合元素的remove,当集合的结构发生改变时,迭代器必须重新获取,如果还是用以前老的迭代器,会出现异常:java.util.ConcurrentModificationException
(3)在迭代集合元素的过程中,不能调用集合对象的remove方法,删除元素:
例如:c.remove(o);会出现:java.util.ConcurrentModificationException
(4)在迭代元素的过程当中,一定要使用迭代器Iterator的remove方法,删除元素,
例如:it.remove(),是可以的,因为再删除元素的同时,会把快照里的元素也删除!

package com.bjpowernode.javase.collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;


public class CollectionTest07 {
    public static void main(String[] args) {
        //1、 创建集合,正常打印
        Collection c = new ArrayList();

        // 注意:此时获取的迭代器,指向的是那是集合中没有元素状态下的迭代器。
        // 一定要注意:集合结构只要发生改变,迭代器必须重新获取。
        // 当集合结构发生了改变,迭代器没有重新获取时,调用next()方法时:java.util.ConcurrentModificationException
        //Iterator it = c.iterator();

        // 添加元素
        c.add(1); // Integer类型
        c.add(2);
        c.add(3);

        // 获取迭代器
        Iterator it = c.iterator();
        while(it.hasNext()){
            // 编写代码时next()方法返回值类型必须是Object。
            // Integer i = it.next(); //err
            Object obj = it.next();
            System.out.println(obj);
        }
        
        //2,创建集合,删除集合中的元素
        Collection c2 = new ArrayList();
        c2.add("abc");
        c2.add("def");
        c2.add("xyz");

        Iterator it2 = c2.iterator();
        while(it2.hasNext()){
            Object o = it2.next();
        // 1.使用集合中的remove方法删除,err
        //c2.remove(o); 直接通过集合去删除元素,没有通知迭代器。
        //(导致迭代器的快照和原集合状态不同。)
        // 删除元素之后,集合的结构发生了变化,应该重新去获取迭代器
        // 但是,循环下一次的时候并没有重新获取迭代器,所以会出现异常:java.util.ConcurrentModificationException
            // 出异常根本原因是:集合中元素删除了,但是没有更新迭代器(迭代器不知道集合变化了)
            
        // 2.使用迭代器中的remove方法来删除
        // 迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中的元素)。
            it2.remove(); // 删除的一定是迭代器指向的当前元素。
            System.out.println(o);
        }

        System.out.println(c2.size()); //0,此时迭代器中的元素个数是0
    }
}

🥅List集合

测试List接口中常用方法
(1)List集合存储元素特点:有序可重复
有序:List集合中的元素有下标;从0开始,以1递增。
可重复:存储一个1,还可以再存储1。
(2)List既然是Collection接口的子接口,那么List接口肯定有自己 “特有”的方法

void add(int index, Object element) //1. 在列表指定位置插入指定元素
//这个方法使用不多,因为ArrayList底层是数组,向指定位置插入,效率比较低
Object get(int index) //2.根据下标获取元素
Object set(int index, Object element) //3.根据下标修改元素
Object remove(int index) // 4.通过下标删除指定位置的元素
int indexOf(Object o) //5.获取指定对象第一次出现的索引
int lastIndexOf(Object o) //6.获取指定对象最后一次出现的索引

(3)补充:计算机英语,增删改查这几个单词要知道:
增:add、save、new
删:delete、drop、remove
改:update、set、modify
查:find、get、query、select

package com.bjpowernode.javase.collection;


import java.util.Iterator;
import java.util.List;
import java.util.ArrayList;

public class ListTest01 {
    public static void main(String[] args) {
        // 创建List类型的集合
        List mylist = new ArrayList();

        // 添加元素
        mylist.add("A"); //默认都是在列表的尾部插入指定元素
        mylist.add("B");
        mylist.add("C");
        mylist.add("D");
        mylist.add("C");
        // 1.在列表指定位置插入指定元素
        mylist.add(1,"K");

        //迭代整个集合
        Iterator it = mylist.iterator();
        while (it.hasNext()) {
            System.out.print(it.next()+" "); //A K B C D C
        }
        System.out.println();

        // 2.根据下标获取元素
        System.out.println(mylist.get(0)); // A
        // 因为有下标,所以List集合有自己特殊的遍历方式
        for (int i = 0; i < mylist.size(); i++) {
            System.out.print(mylist.get(i)+" "); //A K B C D C
        }
        System.out.println();

        // 3.根据下标修改元素
        mylist.set(1,"H");
        for (int i = 0; i < mylist.size(); i++) {
            System.out.print(mylist.get(i)+" "); //A H B C D C
        }
        System.out.println();

        // 4.获取指定对象第一次出现的索引
        System.out.println(mylist.indexOf("C")); //3

        // 5.获取指定对象最后一次出现的索引
        System.out.println(mylist.lastIndexOf("C")); //5

        // 6.通过下标删除指定位置的元素
        mylist.remove(0);
        System.out.println(mylist.size()); // 5

    }
}

ArrayList集合

⭐️ArrayList集合初始化容量及扩容

ArrayList集合底层采用了数组这种数据结构ArrayList集合是非线程安全的。
(1)默认初始化容量10(底层先创建了一个长度为0的数组,当添加第一个元素的时候,初始化容量10)
(2)集合底层是一个Object[]数组
(3)构造方法:       

new ArrayList() 默认容量是10
new ArrayList(20) 自己定义容量的大小

(4)ArrayList集合的扩容:增长到原容量的1.5倍
ArrayList集合底层是数组,怎么优化?
尽可能少的扩容。因为数组扩容效率比较低,建议在使用ArrayList集合的时候预估计元素的个数,给定一个初始化容量。
(5)数组优点:检索效率比较高。(每个元素占用空间大小相同,内存地址是连续的,知道首元素内存地址,然后知道下标,通过数学表达式计算出元素的内存地址,所以检索效率最高。)
(6)数组缺点:随机增删元素效率比较低。另外数组无法存储大数据量。(很难找到一块非常巨大的连续的内存空间。)
(7)向数组末尾添加元素,效率很高,不受影响。
(8)这么多的集合中,你用哪个集合最多
答:ArrayList集合是非线程安全的,用的比较多。因为一般都是往末尾添加元素,往数组末尾添加元素,效率不受影响。另外,我们检索/查找某个元素的操作比较多。

package com.bjpowernode.javase.collection;
import java.util.ArrayList;
import java.util.List;

public class ArrayTest01 {
    public static void main(String[] args) {
        //1. 默认初始化容量为10
        List list = new ArrayList();
        // 集合的size()方法是获取当前集合中元素的个数,而不是获取集合的容量
        System.out.println(list.size()); //0
        //2. 指定初始化容量为20
        List list1 = new ArrayList(20);
        System.out.println(list1.size()); //0

    }
}

⭐️ArrayList集合的一个特殊方法,把HashSet集合转换成ArrayList集合

如果把一个HashSet集合里的元素,通过new ArrayList(HashSet集合),就可以把一个HashSet集合转换成ArrayList集合!

package com.bjpowernode.javase.collection;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.ArrayList;

//ArrayList集合的一个特殊方法,参数里面放集合
public class ArrayTest02 {
    public static void main(String[] args) {
        //1.默认初始化容量是10
        List myList = new ArrayList();

        //2.指定初始化容量100
        List myList2 = new ArrayList(100);

        //3.ArrayList参数是一个集合;可以把HashSet集合转换成ArrayList集合
        // 3.1创建一个HashSet集合
        Collection c = new HashSet();
        //  3.2添加元素
        c.add(100);
        c.add(50);
        c.add(200);
        c.add(150);
        //  3.3通过构造方法可以把HashSet集合转换成ArrayList集合
        List myList3 = new ArrayList(c); //50 100 150 200 
        //  3.4遍历打印
        for (int i = 0; i < myList3.size(); i++) {
            System.out.print(myList3.get(i)+" ");
        }

    }
}

LinkedList集合

⭐️单链表数据结构

(1)我们先看一下简单一点的单链表;对于链表数据结构来说:基本的单元是节点Node

(2)对于单链表来说,任何一个节点Node中都有两个属性:

        第一:存储的数据

        第二:下一节点的内存地址

(3)结构图如下:

​编辑

(4)链表的优缺点:

       优点: 随机增删元素效率较低(因为增删元素不涉及到大量元素位移)

       缺点: 查询效率较低,每一次查找某个元素的时候都需要从头结点开始往下遍历

(5)我们就简单先实现一下链表的一个功能,后期更新数据结构在细讲!

(1)Node节点

package com.bjpowernode.javase.collection.list;

/*
单链表中的节点:节点是单向链表中基本的单元。
每一个节点Node都有两个属性:
    一个属性:是存储的数据。
    另一个属性:是下一个节点的内存地址。
 */
public class Node {
    // 存储的数据
    Object data;
    // 下一个节点的内存地址
    Node next;
    //构造方法
    public Node(){

    }
    public Node(Object data, Node next){
        this.data = data;
        this.next = next;
    }
}

 (2)实现功能List

package com.bjpowernode.javase.collection.list;

public class List {
    Node header;  // 头节点,默认是null
    int sz; // 存放元素的个数,默认是0

    //1、 增加元素
    public void add(Object data){
        //如果当前没有节点,那么把第一个节点作为头节点
        if(header == null){
            header = new Node(data,null);
        }else{
            //头结点存在,找到尾结点
            Node lastNode = findLastNOde(header);
            //找到以后进行尾插
            lastNode.next = new Node(data,null);
        }
        sz++; //添加元素就sz++
    }

    //用来找尾结点的方法
    private Node findLastNOde(Node node) {
        //1.利用递归找
/*      if(node.next == null){
            //如果一个节点的next是null,说明这个节点就是末尾节点
            return node;
        }
        return findLastNOde(node.next);
*/

        //2.常规方法查找
        Node cur = node;
        while(cur.next != null){
            cur = cur.next;
        }
        return cur;
    }


    //2、遍历打印当前元素
    public void print(){
        Node cur = header;
        while(cur != null){
            System.out.println(cur.data);
            cur = cur.next;
        }
    }

}

(3)测试

package com.bjpowernode.javase.collection.list;

public class Test {
    public static void main(String[] args) {
        //1、增加元素
        List myList = new List();
        myList.add(100);
        myList.add(50);
        myList.add(200);
        //2、当前元素的个数
        System.out.println(myList.sz);
        //3、遍历打印当前元素
        myList.print();

    }
}

⭐️链表优缺点

(1)链表的优点:
由于链表上的元素在空间存储上内存地址不连续。
所以随机增删元素的时候不会有大量元素位移,因此随机增删效率较高。
在以后的开发中,如果遇到随机增删集合中元素的业务比较多时,建议使用LinkedList。

(2)链表的缺点:
不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。所以LinkedList集合检索/查找的效率较低。

(3)对比:
ArrayList:把检索发挥到极致。(末尾添加元素效率还是很高的)
LinkedList:把随机增删发挥到极致。( LinkedList也是有下标的)
加元素都是往末尾添加,所以ArrayList用的比LinkedList多。

(4)注意: ArrayList之所以检索效率比较高,不是单纯因为下标的原因。是因为底层数组发挥的作用。LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从头节点开始一个一个遍历!

package com.bjpowernode.javase.collection;

import java.util.LinkedList;
import java.util.List;

public class LinkedListTest01 {
    public static void main(String[] args) {
       // LinkedList集合底层也是有下标的。
        List list = new LinkedList();
        list.add("a");
        list.add("b");
        list.add("c");
       // 通过下标的方式打印LinkedList集合,证明LinkedList集合是有下标的
        for(int i = 0; i <list.size(); i++){
            Object obj = list.get(i);
            System.out.println(obj);
        }
    }
}

⭐️LinkedList详解(双链表)

(1)LinkedList集合是双向链表。
(2)对于链表数据结构来说,随机增删效率较高。检索效率较低。
(3)链表中的元素在空间存储上,内存地址不连续。

有了前面单链表的学习,对于双链表我们就很容易理解了;我们先看一下结构图:

​编辑

(1) LinkedList集合没有初始化容量!
(2)最初这个链表中没有任何元素。first和last引用都是null
(3)不管是LinkedList还是ArrayList,以后写代码时不需要关心具体是哪个集合;因为我们要面向接口编程,调用的方法都是接口中的方法。

package com.bjpowernode.javase.collection;

import java.util.LinkedList;
import java.util.List;


public class LinkedListTest01 {
    public static void main(String[] args) {
     
        // 面向接口编程,调用的方法都是接口中的方法。
        //想从数组的存储方式改到链表的存储方式,不需要改其它代码,扩展性很强
        //List list2 = new ArrayList(); // 这样写表示底层你用了数组。
        List list2 = new LinkedList(); // 这样写表示底层你用了双向链表。

        // 以下这些方法你面向的都是接口编程。
        list2.add("123");
        list2.add("456");
        list2.add("789");

        for(int i = 0; i < list2.size(); i++){
            System.out.println(list2.get(i));
        }

    }
}

Vector集合

1、底层也是一个数组。
2、初始化容量:10
3、Vector集合扩容特点:扩容之后是原容量的2倍。
4、ArrayList集合扩容特点:扩容是原容量1.5倍。
5、Vector中所有的方法都是线程同步的,都带有synchronized关键字,是线程安全的。效率比较低,使用较少。
6、怎么将一个线程不安全的ArrayList集合转换成线程安全的呢?
通过使用集合工具类:java.util.Collections;

      通过Collections.synchronizedList(集合);就可以把线程不安全变为线程安全啦!
java.util.Collection 是集合接口。
java.util.Collections 是集合工具类。

package com.bjpowernode.javase.collection;

import java.util.*;

public class VectorTest01 {
    public static void main(String[] args) {
        // 创建一个Vector集合
        Vector vector = new Vector();

        // 添加元素
        vector.add(1);
        vector.add(2);
        vector.add(3);
        vector.add(4);
        vector.add(5);
        vector.add(6);
        vector.add(7);
        vector.add(8);
        vector.add(9);
        vector.add(10);

        // 满了之后扩容(扩容之后的容量是20.)
        vector.add(11);

        //遍历打印
        Iterator it = vector.iterator();
        while(it.hasNext()){
            Object obj = it.next();
            System.out.println(obj);
        }

        //从非线程安全变为线程安全
        List myList = new ArrayList(); //非线程安全的
        //变成线程安全的
        Collections.synchronizedList(myList);
        // myList集合就是线程安全的了。
        myList.add("111");
        myList.add("222");
        myList.add("333");

    }
}

🥅Set集合 

对于Set集合里的接口和类,实际上是和Map集合一一对应的!我们这里只演示一下简单的使用,后期在讲Map集合在细讲!

HashSet集合

(1)实际上HashSet集合在new的时候,底层实际上new了一个HashMap集合

(2)放到HashSet集合中的元素实际上是放到HashMap集合的key部分了

(3)HashSet集合特点:无序不可重复

(4)HashSet集合初始化容量是16;初始化容量建议是2的倍数

(5)扩容:扩容之后是原容量的2倍

package com.bjpowernode.javase.collection;

import java.util.Set;

public class HashSet {
    public static void main(String[] args) {
        Set<String> strs = new java.util.HashSet<>();

        //添加元素
        strs.add("hello3");
        strs.add("hello4");
        strs.add("hello1");
        strs.add("hello2");
        strs.add("hello3");
        strs.add("hello3");
        strs.add("hello3");
        strs.add("hello3");

        //遍历
        for(String s:strs){
            System.out.println(s);
        }
    }
}
 /*
        hello1
        hello4
        hello2
        hello3
        1、存储时顺序和取出的顺序不同。
        2、不可重复。
        3、放到HashSet集合中的元素实际上是放到HashMap集合的key部分了。
         */

SortedSet集合

(1)TreeSet集合底层实际上是TreeMap;new TreeSet集合的时候,底层实际上new了一个TreeMap集合。
(2)往TreeSet集合中放数据的时候,实际上是将数据放到TreeMap集合中了;TreeMap集合底层采用了二叉树数据结构。

(3)TreeSet集合存储元素特点:

    无序不可重复的,但是存储的元素可以自动按照大小顺序排序!称为:可排序集合。

    无序:这里的无序指的是存进去的顺序和取出来的顺序不同。并且没有下标。

package com.bjpowernode.javase.collection;

import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest01 {
    public static void main(String[] args) {
        Set<String> strs = new TreeSet<>();

        // 添加元素
        strs.add("A");
        strs.add("B");
        strs.add("Z");
        strs.add("Y");
        strs.add("Z");
        strs.add("K");
        strs.add("M");

        // 遍历
        for(String s:strs){
            System.out.println(s);
        }
    }
}
  /*
            A
            B
            K
            M
            Y
            Z
        从小到大自动排序!
 */