6:容器(一)

数组的length属性返回的是数组的长度,而不是元素的个数

容器在内存中存储,不是磁盘。

6.1 容器的结构

image-20221025155152276

左侧是单例集合,一次存储一个。

右侧是双例集合,一次存储两个元素<K,V>。

6.1.1 单例集合

image-20221025155549652

List接口:存储有序、不可重复、动态数组。

Set接口:存储无序、不可重复、数学中的集合。

6.1.2 双例集合

image-20221025155827748

6.2 单例集合的使用

6.2.1 Collection 中包含的抽象方法

image-20221025160159036

6.2.2 List接口介绍

List接口特点:有序、可重复。

List接口中的常用方法

image-20221025161153980

6.2.3 ArrayList容器类

ArrayList是List接口的实现类。

ArrayList底层是数组实现的。特点:查询效率高、增删效率低、线程不安全。

向ArrayList添加元素:
public class ArrayListTest {
    public static void main(String[] args) {
        //实例化ArrayList容器
        List<String> list = new ArrayList<>();
        //添加元素
        list.add("houyiming");
        //索引的数值不能大于元素的个数
        list.add(2,"11");
    }
}
从ArrayList获取元素:

用get方法

public class ArrayListTest {
    public static void main(String[] args) {
        //实例化ArrayList容器
        List<String> list = new ArrayList<>();
        //添加元素
        list.add("houyiming");
        //索引的数值不能大于元素的个数
        list.add(1,"houerming");
        list.add("housanming");
        System.out.println(list.get(2)); // get()中的数不能越界
    }
}

size()方法:返回列表的元素个数

删除元素

根据索引删除:

E remove(int index) //返回被删除元素

根据元素删除 :

boolen remove(Object o) //返回是否删除成功
替换元素
E set(int index,E element)  
//返回被替换元素 将第index个元素替换为element
清空容器
void clear()
判断容器是否为空
boolean isEmpty()
判断容器中是否包含指定元素
boolean contains(object o)
查找元素的位置
int indexOf(object o) //查找第一次出现的位置
int lastIndexOf(object o)  //查找最后一次出现的位置
将单例集合转换为数组

转换为Object数组

Object[] toArray()   

list.toArray()  // 数组的类型为Object 

转换为泛型类型的数组

<T> T[] toArray(T[] a) 
    
String[] strings =list.toArray(new String[list.size()]);

强制类型转换不能用于数组,将数组批量转换。

容器中的并接操作
boolean addAll(Collection<? extends E> c)

c 不能为空集

容器的交集操作
boolean retainAll(Collection<?> c)
容器的差集操作
boolean removeAll(Collection<?> c)

6.2.4 ArrayList源码分析

ArrayList底层用数组实现

ArrayList中的数组默认长度:

​ 1.7版本为立即初始化,长度为10.

​ 1.8版本为延迟加载,初始化的时候长度为0,用的时候再将长度改为10。 当10不够用的时候,以1.5倍(向下取整)扩容

6.2.5 Vector 容器类

Vector底层也是用数组实现的,在多线程时是线程安全的

image-20221025205845409

6.2.5.1 Vector源码分析

Vector中采用 立即初始化,长度为10.

Vector数组扩容以2倍扩容

6.2.5.2 Stack容器

image-20221026192355773

操作栈的方法

image-20221026192831882

6.2.6 LinkedList 容器类

image-20221026195506297

底层用双向链表实现链表实现

查询效率低,增加删除效率低,线程不安全

LinkedList的独有的方法

image-20221026201412279

LinkedList源码分析

Node类:

image-20221026203833949

链表中添加元素:

image-20221026205402270

头尾添加元素:

image-20221026205711521

尾部添加元素也是调用linkLast()

在指定位置添加元素:

    public void add(int index, E element) {
        checkPositionIndex(index);//检查index的值是否合法

        if (index == size)
            linkLast(element);
        else
            linkBefore(element, node(index));
    }

Node<E> node(int index) {   //查找到第index个节点
        // assert isElementIndex(index);

        if (index < (size >> 1)) {  // 从头找
            Node<E> x = first;
            for (int i = 0; i < index; i++)
                x = x.next;
            return x; 
        } else {   // 从尾部开始找
            Node<E> x = last;
            for (int i = size - 1; i > index; i--)
                x = x.prev;
            return x;
        }
    }

    void linkBefore(E e, Node<E> succ) { // 在上一步找到的节点前链接
        // assert succ != null;
        final Node<E> pred = succ.prev;
        final Node<E> newNode = new Node<>(pred, e, succ);
        succ.prev = newNode;
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        size++;
        modCount++;
    }

获取指定位置元素:

public E get(int index) {
        checkElementIndex(index);
        return node(index).item;
    }

private void checkElementIndex(int index) {
        if (!isElementIndex(index))
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }

删除指定位置元素:

public E remove(int index) {
    checkElementIndex(index);
    return unlink(node(index));
}

    E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }

6.2.7 Set接口

image-20221027144915411

Set特点:无序、不可重复。

Set中常用的实现类:HashSet、TreeSet

6.2.8 HashSet容器类

image-20221027145416012

语序有Null元素,底层用HashMap实现,查询和增删效率都很高。

HashSet的使用

在Set容器中没有get(int index)方法,可以用for each循环。

HashSet存储特征

HashSet是一个不保证元素顺序且没有重复元素出现的的集合,是线程不安全的,允许有null元素。

HashSet底层使用HashMap存储数组,HashMap底层使用链表+数组的实现元素存储。由Hash值确定在数组中的位置,如果不同元素的Hash值相同,则使用拉链法存储

在自定义对象中要重写hashcode和equals方法,才能实现元素不重复。

HashSet底层会对int(0到16)的数据默认进行排序(假排序)

产生假排序的原因:Integer的HashCode方法是直接返回其int值的,然后再模16,得到的结果大小排序于原数据相同。

HashSet的源码分析

HashSet的值存在于HashMap的Key中。

6.2.9 TreeSet容器类

image-20221028100533486

自定义比较规则

image-20221028102203250

在定义类中实现comparable接口中的comparTo类

    // 返回正数 :大  返回复数:小  返回0:相等
    @Override
    public int compareTo(Users o) {
        if (this.u8serAge < o.getU8serAge()){  //年龄小的比较大
            return 1;
        }
        if (this.getU8serAge() == o.getU8serAge()){
            return this.userName.compareTo(o.getUserName());
        }
        return -1;
    }
}
通过比较器实现比较规则

image-20221028105626160

public class StudentComparator implements Comparator<Student> {
    @Override
    public int compare(Student o1, Student o2) {
        if (o1.getAge() < o2.getAge()){
            return 1;
        }
        if (o1.getAge() == o2.getAge()){
            return o1.getName().compareTo(o2.getName());
        }
        return 1;
    }
}


Set<Student> s = new TreeSet<>(new StudentComparator());
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐