Java集合框架详解(JDK1.8)带走你的烦恼

目录

1.前言:

2.集合类图概述:

3.接口及类的详解:

1.Iterator接口

2.Iterable接口

3.Collection接口

4.List接口及其实现类

一.ArrayList 类

二.LinkedList类

三.Vector类

四.Stack类

5.Set接口及其实现类

一.HashSet和LinkedHashSet

二.TreeSet类

6.Queue接口及其实现类

7.Deque接口及其实现类

一.ArrayDeque类

二.LinkedList类(此处用来实现双端队列)

8.Map接口及其实现类

一.HashMap类

二.LinkedHashMap类

三.TreeMap类


1.前言:

在jdk1.2之前,Java就提供了诸如:Dictionary, Vector, Stack,这些类用来存储和操作对象组。但是它们缺少一个统一的主题。于是在jdk1.2之后便出现了集合框架,在jdk1.5上又添加了Iterable接口用来实现集合的迭代, 整个集合框架就围绕一组标准接口(例如Set,List) 而设计。你可以直接使用这些接口的标准实现,诸如: LinkedList, HashSet, 和 TreeSet等,除此之外你也可以通过这些接口实现自己的集合。

读者还应注意Java中集合与数组的区别:

  1. 已定义集合的大小可变,而已定义的数组大小不可变(注意:集合内部实现机制也用到了对象数组,只是通过数组的复制或链式存储的方式使其从外部看起来是可变的,而其本身并未颠覆数组大小不可变这一观点)
  2. 数组可以存储基本数据类型和引用类型,而集合只能存储引用类型,例如传入add方法中的int会被自动封装成Integer类型
  3. 数组只能存储相同类型的数据,而集合如未确定泛型的具体类型,则可存储任意引用类型数据

 

2.集合类图概述:

Java集合框架详解(JDK1.8)带走你的烦恼_第1张图片

(注:1.此图只显示类常用接口和类,省略了部分中间类,将在下文逐一说明。2.Map族独立于collection,但属于集合框架中的一部分)

 

3.接口及类的详解:

 

1.Iterator接口

首先要注意一点,Iterator接口和Iterable接口没有半毛钱的继承实现关系,唯一的关系是,在Iterable接口中有一个可返回Iterator类型的方法iterator()。 Iterator是一个集合的迭代器,通俗的说,它可将集合中的元素逐次取出,常用方法如下:

boolean hasNext() 如果还可以迭代下一个元素,则返回true
E next() 返回迭代中的下一个元素

2.Iterable接口

Collection族下的类都间接实现此接口,实现此接口允许对象成为“for-each loop”语句的目标

接口中两个最常用的方法如下:

default void forEach(Consumer action 对 Iterable 的每个迭代元素执行给定的操作,传入一个函数的引用
Iterator iterator() 返回类型为 T 的迭代器

代码示例:

public static void main(String[] args) {
        ArrayList arrayList=new ArrayList();
        arrayList.add(520);
        arrayList.add(true);
        arrayList.add(new Date());

        arrayList.forEach(System.out::println);
        Iterator iterator=arrayList.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第2张图片

 

3.Collection接口

集合层次结构中的根接口 。 集合表示一组被称为其元素的对象。 一些集合允许重复元素,而其他集合不允许。JDK不提供此接口的任何直接实现:它提供了更具体的子接口的实现,如Set和List 等,常用扩展方法如下:

boolean add(E e) 添加元素
boolean addAll(Collection c) 将指定集合中的所有元素添加到该集合中
void clear() 删除此集合中的所有元素
boolean contains(Object o) 判断此集合是否包含指定元素,对比方式是equals(Object o)
boolean isEmpty() 判断集合是否为空
boolean remove(Object o) 成功返回true,如果删除失败或者该元素不存在,返回false
boolean removeAll(Collection c) 删除本集合中与给定集合的交集
boolean retainAll(Collection c) 保存本集合中与给定集合的交集
int size() 返回此集合中的元素数
Object[] toArray() 返回一个包含此集合中所有元素的对象数组

4.List接口及其实现类

首先说明List与Set的区别:

 
List Set
元素有序(存入取出位置不变) 元素无序
元素存在唯一的索引值 不存在索引
允许重复元素 不允许重复元素

在Collection基础上,List扩展的如下方法:

void add(int index,E element) 将元素插入指定的位置
boolean addAll(int index,Collection c) 按指定集合的迭代器顺序将其添加到本元素的指定位置
E get(int index) 返回此列表指定位置的元素

int indexOf(Object o)

int lastIndexOf(Object o)

返回此列表中指定元素第一次(最后一次)出现的位置

如果不存在则返回-1

ListIterator listiterator()

ListIterator listiterator(int index)

返回此列表中的列表迭代器

从指定位置开始返回迭代器

E remove(int index) 删除指定位置的元素,并返回到该元素
default void sort(Comparator c)  使用随附的 Comparator排序此列表来比较元素。  
List subList(int fromIndex, int toIndex)  返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。  

注:ListIterator 接口继承自 Iterator,它允许沿任一方向遍历列表

代码示例:

 public static void main(String[] args) {
        ArrayList arrayList=new ArrayList();
        arrayList.add(520);
        arrayList.add(43);
        arrayList.add(321);
        arrayList.add(0,999);
        arrayList.add(334);
        System.out.println("原始数组:");
        arrayList.forEach(System.out::println);
        System.out.println("获取第3个元素:"+arrayList.get(2));
        System.out.println("a的位置:"+arrayList.indexOf(520));
        System.out.println("排序后:");
        arrayList.sort(Comparator.comparing(Integer::intValue));
        arrayList.forEach(System.out::println);
        System.out.println("ListIterator迭代:");
        ListIterator listIterator=arrayList.listIterator();
        while(listIterator.hasNext()){
            System.out.println(listIterator.next());
        }
        System.out.println("删除第3个位置的元素:"+arrayList.remove(2));
        System.out.println("新建数组内容为");
        List list=arrayList.subList(1,3);
        list.forEach(System.out::println);
    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第3张图片

 

一.ArrayList 类

实现List接口,并允许所有元素,包括null,每个ArrayList实例都有一个容量 。 容量是用于存储列表中的元素的数组的大小。 它总是至少与列表大小一样大。 当元素添加到ArrayList时,其容量会自动增长。 没有规定增长的细节

此处说明:

ArrrayList与Vector的区别:1.ArrayList不是线程同步的,而Vector是线程同步的。2.ArrayList默认扩容量是原来的0.5倍,而Vector的默认扩容是原来的一倍

ArrayList与LinkedList的区别:ArrayList由数组备份。LinkedList由链接备份,并且LinkedList还可以用作队列。访问ArrayList中的元素更快,因为它的底层结构是数组,而当集合要频繁的进行增删,LinkedList 的性能优于 ArrayList 。

继承关系:

Java集合框架详解(JDK1.8)带走你的烦恼_第4张图片

构造方法:

ArrayList()  构造一个初始容量为十的空列表。  
ArrayList(Collection c)  构造一个包含指定集合的元素的列表,按照它们由集合的迭代器返回的顺序。  
ArrayList(int initialCapacity)  构造具有指定初始容量的空列表。 

扩展方法:

Object clone()  返回此 ArrayList实例的浅拷贝(关于深浅拷贝的区别见下文)
void ensureCapacity(int minCapacity)  增加此 ArrayList实例的容量,以确保它可以至少保存最小容量参数指定的元素数
void trimToSize()  修改这个 ArrayList实例的容量是列表的当前大小
void replaceAll(UnaryOperator operator)  将该列表的每个元素替换为将该运算符应用于该元素的结果
E set(int index, E element) 用指定的元素替换此列表中指定位置的元素

注:浅拷贝:被复制对象与原对象在内存中的引用是同一个对象

       深拷贝:在内存中新开辟一块空间,把要复制的对象所引用的对象都复制了一遍,对现在对象的修改不会影响原有的对象。

代码示例:

public class Main {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList(100);
        People people1 = new People(66);
        arrayList.add(people1);
        arrayList.add(new People(47));
        arrayList.add(new People(33));
        arrayList.set(2,new People(55));
        people1.setAge(100);
        arrayList.forEach(System.out::println);
        System.out.println("拷贝数组");
        ArrayList clonearray = (ArrayList) arrayList.clone();
        clonearray.forEach(System.out::println);
        System.out.println("将people的值改变后:");
        people1.setAge(888);
        clonearray.forEach(System.out::println);
    }
}
class People {
    int age;
    public People(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "People{" +
                "age=" + age +
                '}';
    }
}

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第5张图片

二.LinkedList类

LinkedList是非线程同步的,LinkedList与ArrayList的区别上文已讲,而当集合要频繁的进行增删,建议使用LinkedList提高性能,由于LinkeList还是同时实现了List和Deque接口,所以它还可以用来表示队列,具体实现在下文Queue接口和Deque接口中

类图结构:

Java集合框架详解(JDK1.8)带走你的烦恼_第6张图片

 

三.Vector类

Vector在共功能上与ArrayList相似,如果不需要线程安全的实现,建议使用ArrayList代替Vector

构造方法如下:

Vector()  构造一个空向量,使其内部数据数组的大小为 10 ,标准容量增量为零
Vector(Collection c)  构造一个包含指定集合元素的向量,按照集合的迭代器返回的顺序。
Vector(int initialCapacity)  构造具有指定初始容量并且其容量增量等于零的空向量。  
Vector(int initialCapacity, int capacityIncrement)  构造具有指定的初始容量和容量增量的空向量。

成员方法略

四.Stack类

Stack是一个后进先出的栈(LIFO),但Deque接口及其实现提供了更完整和一致的LIFO堆栈操作集,这些接口应优先于此类。 例如: Deque stack = new ArrayDeque(); 

Stack继承自Vector,扩展方法如下:

boolean empty()  测试此堆栈是否为空。  
E peek()  查看此堆栈顶部的对象,而不从堆栈中删除它。
E pop()  删除此堆栈顶部的对象,并将该对象作为此函数的值返回。  
E push(E item) 将项目推送到此堆栈的顶部。  
int search(Object o) 返回一个对象在此堆栈上的基于1的位置

代码示例:

private static void showpush(Stack st, int a) {//把项压入栈顶
        st.push(new Integer(a));
        System.out.println("push(" + a + ")");
        System.out.println("stack: " + st);
    }
    private static void showpop(Stack st) {//移除堆栈顶部的对象并作为此函数的值返回该对象
        Integer a = (Integer) st.pop();
        System.out.println(a);
        System.out.println("after pop stack: " + st);
    }
    private  static void showpeek(Stack stack){
        Integer a=(Integer) stack.peek();
        System.out.println(a);
        System.out.println("after peek stack:"+stack);
    }
    public static void main(String args[]) {
        Stack st = new Stack();
        System.out.println("stack: " + st);
        showpush(st, 42);
        showpush(st, 66);
        showpush(st, 99);
        showpeek(st);
        showpop(st);
        showpop(st);
        showpop(st);
        try {
            showpop(st);
        } catch (EmptyStackException e) {
            System.out.println("empty stack");
        }
    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第7张图片

 

 

5.Set接口及其实现类

Set集合是唯一元素集合,最多只有一个null值,当向集合添加重复元素时,它们将被忽略,元素是否相同是通过equals()方法实现的

一.HashSet和LinkedHashSet

区别:HashSet 不保证顺序元素。 LinkedHashSet 在插入元素时保持元素顺序

代码示例:

    public static void main(String[] args) {
        Set hashSet=new HashSet();
        hashSet.add("XML");
        hashSet.add("HTML");
        hashSet.add("SQL");
        hashSet.add(null);
        hashSet.add("HTML");
        hashSet.add(null);
        hashSet.add("JAVA");
        System.out.println("hashSet:"+hashSet);
        HashSet linkHashSet=new LinkedHashSet<>();
        linkHashSet.add("XML");
        linkHashSet.add("HTML");
        linkHashSet.add("SQL");
        linkHashSet.add(null);
        linkHashSet.add("HTML");
        linkHashSet.add(null);
        linkHashSet.add("JAVA");
        System.out.println("LinkedHashSet:"+linkHashSet);
    }

运行结果:

二.TreeSet类

SortedSet 接口表示Java集合中的排序集合框架,如果它的元素实现了Comparable接口,它将使用compareTo()方法来排序项目。 我们可以称之为自然顺序排序。我们也可以传递一个比较器Comparator做自定义排序。如果指定了 Comparator ,则将Comparator 用于排序并忽略 Comparable 接口。
TreeSet 类是Collection框架中SortedSet接口的一个实现。

类图结构:

Java集合框架详解(JDK1.8)带走你的烦恼_第8张图片

代码示例:

public class Main {
    public static void main(String[] args) {
     /*   按照String中的compareTo的默认比较方法
        先比较字符串长度,如果长度一样,则按照字典的顺序依次比较,小写大于大写*/
        SortedSet sortedSet=new TreeSet();
        sortedSet.add("jav");
        sortedSet.add("hdTM");
        sortedSet.add("xML");
        sortedSet.add("sQL");
        System.out.println(sortedSet);
        /*
        使用Comparable比较器自定义排序关键字
         */
        SortedSet students=new TreeSet<>(Comparator.comparing(Student::getAge));
        students.add(new Student("Kangkang",13));
        students.add(new Student("Mike",11));
        students.add(new Student("Jack",18));
        students.add(new Student("Lihua",14));
        System.out.println("将学生按年龄排序:");
        students.forEach(System.out::println);
    }
}
class Student{
    String name;
    int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第9张图片

6.Queue接口及其实现类

简单队列用 Queue接口表示,并由LinkedList实现

简单队列队列允许您执行三个基本操作:

  • 从尾部添加元素
  • 从其头部移除元素
  • 在元素顶部审查

Queue接口为三个操作中的每一个定义了两个方法。如果操作不可能,一个方法抛出异常,另一个方法方法返回false或null以指示失败。

方法 描述
boolean add(E e) 如果可能,向队列中添加一个元素。否则,它抛出异常。
boolean offer(E e) 如果不能添加元素,则将元素添加到队列中,而不抛出异常。 它在失败时返回false,在成功时返回true。
E remove() 删除队列的头。如果队列为空,它会抛出异常。此方法返回已移除的项目。
E poll() 从队列中删除元素。如果队列为空而不是抛出异常,则返回null。
Eelement() 偷看队列的头,而不从队列中删除它。 如果队列为空,它会抛出异常。
E peek() 查看队列,如果队列为空而不是抛出异常,则返回null。

代码示例:

public static void main(String[] args) {
        Queue queue = new LinkedList<>();
        queue.offer("one");
        queue.offer("two");
        queue.offer("three");
        queue.offer("four");
        System.out.println(queue);
        //出队
        System.out.println("使用poll()"+queue.poll());
        System.out.println(queue);
        System.out.println("使用peek()"+queue.peek());
        System.out.println(queue);
    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第10张图片

 

7.Deque接口及其实现类

双端队列或Deque扩展队列以允许元件从两端插入和移除。
Deque 类的实例表示双端队列。 Deque 接口扩展了 Queue 接口。
它可以用作 FIFO队列  LIFO队列(堆栈)
ArrayDeque和LinkedList类是Deque接口的两个实现类。
ArrayDeque 类由数组支持,而 LinkedList 类由链表支持。
如果您使用Deque作为堆栈,则应该使用 ArrayDeque 作为 Deque 实现。
如果使用 Deque 作为FIFO队列,则应该使用 LinkedList 作为 Deque 实现。

一.ArrayDeque类

常用方法:

用作 LIFO 栈结构
E peek()  检索但不删除栈顶
void push(E e) 将元素压入栈
E pop()   弹出栈顶元素

代码示例:

public static void main(String[] args) {
        Deque deque=new ArrayDeque();
        deque.push("one");
        deque.push("two");
        deque.push("three");
        deque.push("four");
        System.out.println(deque);
        System.out.println("使用peek():"+deque.peek());
        System.out.println(deque);
        System.out.println("使用pop():"+deque.pop());
        System.out.println(deque);

    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第11张图片

二.LinkedList类(此处用来实现双端队列)

常用方法:

LinkedList实现双端列表
void addFirst(E e) 在该列表开头插入指定的元素
void addLast(E e) 将指定的元素追加到此列表的末尾
E peekFirst()  检索但不删除此列表的第一个元素,如果此列表为空,则返回 null
E peekLast() 检索但不删除此列表的最后一个元素,如果此列表为空,则返回 null
E pollFirst() 检索并删除此列表的第一个元素,如果此列表为空,则返回 null
E pollLast() 检索并删除此列表的最后一个元素,如果此列表为空,则返回 null 

代码示例:

 public static void main(String[] args) {
        Deque deque=new LinkedList<>();
        deque.addFirst("左一");
        deque.addFirst("左二");
        deque.addFirst("左三");
        deque.addLast("右一");
        deque.addLast("右二");
        deque.addLast("右三");
        System.out.println(deque);
        System.out.println("peekFirst():"+deque.peekFirst());
        System.out.println(deque);
        System.out.println("peekLast():"+deque.peekLast());
        System.out.println(deque);
        System.out.println("pollFirst():"+deque.pollFirst());
        System.out.println(deque);
        System.out.println("pollLast():"+deque.pollLast());
        System.out.println(deque);
    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第12张图片

 

 

8.Map接口及其实现类

敲黑板!:Map是Mapping(映射)的简写,不要以为是数据结构中的 Map(图)

Map是一个集合,其中每个元素表示一个键值对作为 对也称为映射中的条目,由Map中的一个内部接口Entry表示。键和值必须是引用类型,Map接口虽和Collection没啥关系,但它仍是集合框架中很重要的一部分,映射不允许任何重复的键。每个键映射到正好一个值。值不必是唯一的。 两个键可以映射到相同的值,Map允许最多一个null作为键,允许多个null作为其值

首先我们了解代表Map集合中每个映射条目的内部接口Map.Entry,常用方法如下;

K getKey() 获取该条目中的键
V getValue() 获取该条目中的值
int hashCode() 返回此条目的哈希值
V setValue(V value) 使用指定的值替换该条目中的值

代码示例:(获取条目的唯一方法是使用Map.entrySet() )

public static void main(String[] args) {
        Map map=new HashMap();
        map.put(1,"one");
        map.put(2,"two");
        map.put(3,"three");
        map.put(4,"four");
        Set entrySet=map.entrySet();
        Iterator iterator=entrySet.iterator();
        while(iterator.hasNext()){
            Map.Entry entry1=iterator.next();
            System.out.println(entry1.getKey()+"==="+entry1.getValue());
            entry1.setValue("hello world");
        }
        System.out.println(map);
}

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第13张图片

由结果可见,entrySet存储的原Map中的视图,从而实现对Map中元素的迭代和修改,Map接口本身是不具备迭代功能的,除了使用entrySet()外,使用keySet()和values()分别获取键,值的视图也是迭代的不错的选择。

Map接口中的常用方法如下:

V put(K key, V value)  向集合中添加映射项目
void putAll(Map m) 将指定Map中的值复制到此映射
void clear() 从集合中删除所有的映射
boolean containsKey(Object key) 判断集合中是否包含此键的映射
boolean containsValue(Object value) 判断集合中是否包含此值的映射
Set keySet() 返回由Map中的键组成的集合视图
Collection values() 返回由Map中的值组成的集合视图
Set> entrySet() 返回由Map中的映射条目组成的集合视图

Map常用的实现类:

一.HashMap类

HashMap不保证Map中条目的任何特定的迭代顺序

代码示例:

 public static void main(String[] args) {
        Map map=new HashMap();
        map.put(9,"one");
        map.put(2,"two");
        map.put(6,"three");
        map.put(4,"four");
        System.out.println(map);
        System.out.println("判断集合中是否包含键为2的映射:  "+map.containsKey(2));
        System.out.println("判断集合中国是否包含值为three:  "+map.containsValue("three"));
        Set set=map.keySet();
        System.out.println(set);
        Collection collection=map.values();
        System.out.println(collection);
    }

运行结果:

Java集合框架详解(JDK1.8)带走你的烦恼_第14张图片

二.LinkedHashMap类

LinkedHashMap是Map接口的另一个实现类,继承自HashMap, 它使用双向链表在Map中存储条目,并保持迭代排序作为插入顺序

代码示例:

 public static void main(String[] args) {
        Map map=new LinkedHashMap();
        map.put(9,"one");
        map.put(2,"two");
        map.put(6,"three");
        map.put(4,"four");
        System.out.println(map);
        System.out.println("判断集合中是否包含键为2的映射:  "+map.containsKey(2));
        System.out.println("判断集合中国是否包含值为three:  "+map.containsValue("three"));
        Set set=map.keySet();
        System.out.println(set);
        Collection collection=map.values();
        System.out.println(collection);
    }

Java集合框架详解(JDK1.8)带走你的烦恼_第15张图片

三.TreeMap类

TreeMap是基于一个红黑树的实现,具体继承关系如下,它会按照你对Comparable接口或Comparator比较器的实现来对集合中的条目进行排序,同TreeSet相似,如果你设置了Comparator比较器,Comparable接口的功能将会被忽略。

Java集合框架详解(JDK1.8)带走你的烦恼_第16张图片

下面的代码使用Comparator比较器对TreeMap中的条目进行排序:

public static void main(String[] args) {
        //先比较键的长度,再忽略大小比较
        Comparator keyComparator  = Comparator.comparing(String::length).thenComparing(String::compareToIgnoreCase);
        Map map=new TreeMap(keyComparator);
        map.put("one",3);
        map.put("two",4);
        map.put("three",2);
        map.put("four",1);
        System.out.println(map);
    }

运行结果:

四.HashTable与HashMap的区别

HashTable直接实现Map接口,它与HashMap的区别如下:

  • HashMap去掉了HashTable 的contains方法,但是加上了containsValue()和containsKey()方法。
  • HashTable同步的,而HashMap是非同步的,效率上比HashTable要高。
  • HashMap允许空键值,而HashTable不允许。
     

4.Collections集合工具类

详见我的另一博文:https://blog.csdn.net/qq_42013035/article/details/103452711

 

                               谢谢!OK点个赞!如有不妥,望请路过的大佬指出!

Java集合框架详解(JDK1.8)带走你的烦恼_第17张图片

                                                                                               

 

 

你可能感兴趣的:(java基础,Java集合框架,Java集合类图,List,Set,ArrayList)