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.集合类图概述:

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

 

3.接口及类的详解:

 

1.Iterator<E>接口

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

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

2.Iterable接口

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

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

default void forEach(Consumer<? super T> action对 Iterable 的每个迭代元素执行给定的操作,传入一个函数的引用
Iterator<T> 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());
        }
    }

运行结果:

 

3.Collection接口

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

boolean add(E e)添加元素
boolean addAll(Collection<? extends E> 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的区别:

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

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

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

int indexOf(Object o)

int lastIndexOf(Object o)

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

如果不存在则返回-1

ListIterator<E> listiterator()

ListIterator<E> listiterator(int index)

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

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

E remove(int index)删除指定位置的元素,并返回到该元素
default void sort(Comparator<? super E> c) 使用随附的 Comparator排序此列表来比较元素。  
List<E> 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);
    }

运行结果:

 

一.ArrayList 类

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

此处说明:

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

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

继承关系:

构造方法:

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

扩展方法:

Object clone() 返回此 ArrayList实例的浅拷贝(关于深浅拷贝的区别见下文)
void ensureCapacity(int minCapacity) 增加此 ArrayList实例的容量,以确保它可以至少保存最小容量参数指定的元素数
void trimToSize() 修改这个 ArrayList实例的容量是列表的当前大小
void replaceAll(UnaryOperator<E> 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 +
                '}';
    }
}

运行结果:

二.LinkedList类

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

类图结构:

 

三.Vector类

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

构造方法如下:

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

成员方法略

四.Stack类

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

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");
        }
    }

运行结果:

 

 

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接口的一个实现。

类图结构:

代码示例:

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<Student> 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 +
                '}';
    }
}

运行结果:

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<String> 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);
    }

运行结果:

 

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<String> 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);

    }

运行结果:

二.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<String> 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);
    }

运行结果:

 

 

8.Map接口及其实现类

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

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

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

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<Map.Entry> entrySet=map.entrySet();
        Iterator<Map.Entry> 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);
}

运行结果:

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

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

V put(K key, V value) 向集合中添加映射项目
void putAll(Map<? extends K,? extends V> m)将指定Map中的值复制到此映射
void clear()从集合中删除所有的映射
boolean containsKey(Object key)判断集合中是否包含此键的映射
boolean containsValue(Object value)判断集合中是否包含此值的映射
Set<K> keySet()返回由Map中的键组成的集合视图
Collection<V> values()返回由Map中的值组成的集合视图
Set<Map.Entry<K,V>> 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<Integer> set=map.keySet();
        System.out.println(set);
        Collection<String> collection=map.values();
        System.out.println(collection);
    }

运行结果:

二.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<Integer> set=map.keySet();
        System.out.println(set);
        Collection<String> collection=map.values();
        System.out.println(collection);
    }

三.TreeMap类

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

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

public static void main(String[] args) {
        //先比较键的长度,再忽略大小比较
        Comparator<String> 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点个赞!如有不妥,望请路过的大佬指出!

                                                                                               

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值