当前位置: 首页 > news >正文

Java 集合介绍

一、集合介绍

1、介绍

集合又称容器,是Java中对数据结构(数据存储方式)的具体实现。
我们可以利用集合存放数据,也可以对集合进行新增、删除、修改、查看等操作。
集合数据都是在内存中,当程序关闭或重启后集合中数据会丢失,所以集合是一种临时存储数据的容器。

2、JDK中集合结构图

集合作为一个容器,可以存储多个元素,但是由于数据结构的不同,Java提供了多种集合类,将集合类中共性的功能,不断向上抽取,最终形成了集合体系结构。
在这里插入图片描述

2.1 List 接口和 Set 接口

1、 List 接口:存储有序(插入顺序),可重复数据
  • Vector: List 的实现类,底层为可变长度数据实现。所有方法都是同步操作(线程安全),每次扩容成本增长。新数组长度为原数组长度的2倍。
  • ArrayList:List 实现类,底层为可变长度数组实现。所有方法都是非同步操作(非线程安全的),以1.5倍的方式在扩容。常用于:较多查询的情况。
  • LinkedList:List的实现类,双向非循环链表的实现。常用于:删、增较多的情况。
    总结
    ArrayList 和 Vector比较
    相同点:
    底层都是可变长数组实现,存储的元素有序可重复
    不同点:
    ArrayList 扩容后为之前长度的 1.5倍,非同步操作(线程不安全),性能更好
    Vector扩容后为之前长度的 2 倍,同步操作(线程安全),性能差
    ArrayList 和 LinkedList:
    相同点:
    存储的元素有序可重复,都是非同步操作(线程不安全)
    不同点:
    底层实现不同,ArrayList 数组实现,LinkedList 双向链表实现
2、Set 接口:存储无序,不可重复数据
  • HashSet:Set 实现类,底层是 HashMap 散列表(数组 + 链表 + 红黑树 jdk1.8及之后)。所有添加到 HashSet 中的元素实际存储到了 HashMap 的 key中。
  • LinkedHashSet:HashSet 子类,使用 LinkedHashMap 来存储它的元素,存储的值插入到 LinkedHashMap 的可以 key中,底层实现(数组 + 链表 + (红黑树 jdk1.8及之后)+ 链表),可以记录插入的顺序
  • TreeSet:Set 实现类,底层是 TreeMap(红黑树实现),存入到 TreeSet 中的元素,实际存储到了 TreeMap 中,根据存储元素的大小可以进行排序。
    总结
    ArrayList 和 HashSet
    不同点:ArrayList 存储的数据有序有下标,元素可以重复(底层原因,使用的是数组),可以根据下标获取,HashSet 存储的元素没有下标,没有顺序,元素不可以重复(底层原因,使用 HashMap 存储 数组 + 链表 + (红黑树jdk1.8)之后)
    LinkedHashSet 和 TreeSet
    相同点:有顺序
    不同点:LinkedHashSet 底层 LinkedHashMap 保证插入的顺序
    TreeSet 底层 TreeMap(红黑树)保证 key 值大小的顺序。

2.2 Map 接口

Map:独立的接口。每个元素都包含key(名称)和 value(要存储的值)两个值。

  • HashMap:Map 实现类,对散列表(数组+链表+(红黑树 jdk1.8及之后))的具体实现,非同步操作(非线程安全的)。存储时以Entry 类型存储(key, value)
  • LinkedHashMap:HashMap 的子类,是基于 HashMap 和链表来实现的。在 HashMap 存储结构值上再添加链表,链表只是为了保证顺序
  • TreeMap:Map 实现类,使用的不是散列表,而是对红黑树的具体实现。根据 key 值的大小,放入红黑树中,可实现排序的功能(key 值大小排序)
  • HashTable:Map 实现类,和 HashMap 数据结构一样,采用散列表(数组 + 链表 + (红黑树 jdk1.8及之后))的方法实现,对外提供的 public 函数几乎都是同步的 (线程安全)。
    总结
    HashMap 和 HashTable
    相同点:
    存储的数据结构一样,插入的数据无序
    不同点:
    - HashMap 非同步操作(线程不安全),HashTable 同步操作(线程安全)
    - HashMap 允许只能有一个 key 为 null 值,因为 hashmap 如果 key 值相同,新的 value 将替代旧的。HashTable 不允许 null 值
    LinkedHashMap 和 TreeMap
    相同点:有顺序
    不同点:
    - 底层实现不同
    - LinkedHashMap 通过(数组 + 链表 + (红黑树 jdk1.8 及之后))和 链表保证插入的顺序,TreeMap 通过红黑树保证 key 值大小的顺序
    常用的集合:ArrayList,HashMap,HashSet

Collection 接口

1、接口

List 和 Set 接口的父接口,还有其他的实现类或子接口。

2、继承关系

在这里插入图片描述

3、包含的API

泛型中<? extends E> 代表:只要 E 类型或 E 类型的子类都可以
在这里插入图片描述

三、List接口

1、介绍

Collection 接口的子接口。Collection 中包含的内容 List 接口中可以继承。
List 专门存储有序,可重复数据的接口

2、包含的 API

在这里插入图片描述

四、ArrayList

1、介绍

实现了List接口,实现底层数组扩容
存储有序、可重复数组,有下标

2、实例化

常用向上转型进行实例化。绝大多数集合都支持泛型,如果不写泛型认为泛型是,使用集合时建议一定要指定泛型。
List<泛型类型> 对象 = new ArrayList<>()

3、内存结构图

在这里插入图片描述

4、常用 API

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;

public class TestArrayList {
    /*
    * ArrayList 的基本使用:
    *   ArrayList 自身可以动态调整大小
    *   ArrayList 的内部使用数组存储元素,当数组将被存满,就会创建一个新数组,其容量是当前数组的 1.5 倍
    *       同时,所有元素都将移至新数组,假设内部数组已满,而我们现在又添加了一个元素,ArrayList 容量就会以相同
    *       的比例扩展(在这种情况下,内部数组中将有一些未分配的空间)。此时,trimToSize()方法可以删除未分配的空间
    *       并更改 ArrayList 的容量,使其等于 ArrayList 中的元素个数
    * */
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        //1.增加元素
        list.add("Tom");
        list.add("Marry");
        list.add("Andy");
        list.add("Jhon");
        System.out.println(list);
        //2.访问元素
        /*System.out.println(list.get(1));*/  // 通过元素下标访问第二个元素
        //3.修改元素
       /* list.set(1, "ZS");
        System.out.println(list);*/
        //4.删除元素
        /*list.remove(1);
        System.out.println(list);*/
        //5.计算大小
        /*int length = list.size();
        System.out.println(length);*/
        //6、迭代数组列表
        /*for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }*/
        //7.使用for-each 来迭代元素
        /*for (String s : list) {
            System.out.println(s);
        }*/
        //8.ArrayList 排序
        //8.1 使用 Arrays 自带方法 sort
        //正序
        /*list.sort(Comparator.naturalOrder());
        System.out.println(list);
        //倒序
        list.sort(Comparator.reverseOrder());
        System.out.println(list);*/
        //9.插入元素到指定为止
        /*list.add(2, "Pm");
        System.out.println(list.toString());*/
        //10.添加集合中所有元素到 arrayList 中
        /*ArrayList<String> list1 = new ArrayList<String>();
        list1.add("GOD");
        list1.add("SD");
        //把 list1 所有元素添加到 list 中
        list.addAll(list1);
        // 在指定位置插入 list1
        list.addAll(2, list1);
        System.out.println(list);*/
        //11.删除 arrayList 中所有的元素
        //list.clear();
        /*list.removeAll(list);
        System.out.println("所有 clear() 方法后: " + list);*/
        //12.赋值一份 arrayList
        //clone 属于浅拷贝,浅拷贝只是赋值指向某个对象的指针,而不复制对象本身,新旧对象还是共享一块内存,
        // 所以如果期中一个对象改变了这个地址,就会影响到另一个对象
        //浅拷贝对应的就是深拷贝,深拷贝是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,
        //且修改新对象不会影响原对象
        /*ArrayList<String> cloneList = (ArrayList<String>)list.clone();
        System.out.println("拷贝 ArrayList:" + cloneList);*/
        //13.判断元素是否存在于 arrayList 中
        /*System.out.println("Marry 是否存在于 arrayList中");
        System.out.println(list.contains("Marry"));*/
        //14.获取元素的索引值
        /*int index = list.indexOf("Marry");
        System.out.println("Marry 的索引位置: " + index);*/
        //15.判断 arrayList 是否为空
        /*System.out.println("arrayList 是否为空: " + list.isEmpty());*/
        //16.截取 ArrayList 部分元素
        /*System.out.println("SubList: " + list.subList(0,1));*/
        //17.toArray() 方法将 ArrayList 对象转化为数组
        //创建一个新的 String 类型数组
        /*String[] arr = new String[list.size()];
        list.toArray(arr);
        for (String s : arr) {
            System.out.println(s);
        }*/
        //18.设定指定容量大小的 arrayList
        /*ArrayList<Integer> list2 = new ArrayList<Integer>();
        list2.ensureCapacity(3);
        list2.add(1);
        list2.add(2);
        System.out.println(list2.size());
        System.out.println(list2);*/
        //19.返回指定元素在 arrayList 中最后一次出现的位置
        /*int index = list.lastIndexOf("Marry");
        System.out.println("Marry最后一次出现为止: " + index);*/
        //20.保留 arrayList 中 在指定集合中也存在的那些元素
        //创建另一个动态数组
        /*ArrayList<String> site = new ArrayList<String>();
        site.add("Marry");
        site.add("Jhon");
        //保留元素
        list.retainAll(site);
        System.out.println("保留的元素:" + list);*/
        //21.查看 arrayList 是否包含指定集合中的那些元素
        //创建一个动态数组
        /*ArrayList<String> site = new ArrayList<String>();
        site.add("Marry");
        site.add("Jhon");

        // 检查数组 list 是否包含 site
        boolean b = list.containsAll(site);
        System.out.println(b);*/
        //22.将 arrayList 中的容量调整为数组中的元素个数
        //调整容量
        /*list.trimToSize();
        System.out.println("ArrayList 大小: " + list.size());*/
        //23.删除 arrayList 中指定索引之间存在的元素
        //删除所有满足特定条件的 arraylist 元素
        list.removeIf(e -> e.contains("Jh"));
        System.out.println("删除后的 ArrayList: " + list);

    }
}

五、泛型集合类型

1、介绍

在集合中泛型都是任意引用类型。既然是任意引用类型,也可以是集合类型。

2、实例化语法

List<List<Integer>> list = new ArrayList<>();

3、内存结构图

在这里插入图片描述

4、代码示例

public class Test {
  public static void main(String[] args) {
    List<List<Integer>> list = new ArrayList<>();
    List<Integer> list1 = new ArrayList<>();
    list1.add(1);
    list1.add(2);
    list1.add(3);
    List<Integer> list2 = new ArrayList<>();
    list2.add(11);
    list2.add(22);
    list2.add(33);
    list.add(list1);
    list.add(list2);
    for (List<Integer> integerList : list) {
      for (Integer i : integerList) {
        System.out.println(i);
      }
    }
  }
}

六、LinkedList

1、介绍

LinkedList 是 Java 中对双向非循环链表的实现,实现了List 接口。
具有 ArrayList 所有常用方法,额外还添加了头尾操作方法(实现了 Deque 方法),这些方法在 List 接口是不存在的,所以如果希望使用这些头尾操作方法,实例化时不用向上转型。

2、实例化语法

LinkedList<泛型> 对象 = new LinkedList<>()

3、常用 API

ArrayList 里面常用 API 都可以在 LinkedList 中使用。

public class TestLinkedList {
  public static void main(String[] args) {
    List<String> linkedList = new LinkedList<>();
    linkedList.addFirst("aa");
    linkedList.addLast("bb");

    //获取头结点 没有头结点 java.util.NoSuchElementException
    String first = linkedList.getFirst();
    System.out.println(first);
    //获取尾结点 没有尾结点 java.util.NoSuchElementException
    String last = linkedList.getLast();
    System.out.println(last);

    //获取头结点 没有头结点 返回 null
    String s = linkedList.peekFirst();
    System.out.println(s);
    //获取尾结点 没有尾结点 放回 null
    String s1 = linkedList.peekLast();
    System.out.println(s1);

    //删除头结点 没有头结点 java.util.NoSuchElementException
    String s2 = linkedList.removeFirst();
    System.out.println(s2); //被删除结点中的值
    //删除尾结点 没有尾结点 java.util.NoSuchElementException
    String s3 = linkedList.removeLast();
    System.out.println(s3);//被删除结点中的值
    
    //删除头结点 没有头结点 返回 null
    String s4 = linkedList.pollFirst();
    System.out.println(s4);
    //删除尾结点 没有尾结点 放回 null
    String s5 = linkedList.pollLast();
    System.out.println(s5);

  }
}

七、Set 接口

1、介绍

Set 继承了 Collection 接口,继承的都是 Collection 中的方法,没有提供额外的方法。
Set 经常被称为实现无序,不重复数据集合,指的就是 HashSet 实现类。

2、包含API

在这里插入图片描述

八、HashSet

1、介绍

完全基于 HashMap (数组 + 链表 + 红黑树)实现的。
存储无序,无下标,元素不重复数据

2、代码示例

public class TestHashSet {
  public static void main(String[] args) {
    Set<Integer> set = new HashSet<>();
    //添加元素
    set.add(1);
    set.add(2);
    //元素个数
    int size = set.size();
    //是否包含指定的元素
    boolean contains = set.contains(1);
    ArrayList<Integer> list = new ArrayList<>();
    list.add(3);
    list.add(4);
    list.add(4);
    //将其它集合中的元素添加到set集合中
    set.addAll(list);
    //删除指定的元素
    set.remove(2);
    //查询元素
    for (Integer integer : set) {
      System.out.println(integer);
    }
  }
}

九、TreeSet

1、介绍
底层是基于 TreeMap 红黑树。

public class TestTreeSet {
  public static void main(String[] args) {
    Set<Integer> treeSet = new TreeSet<>();
    treeSet.add(2);
    treeSet.add(1);
    treeSet.add(3);
    //查询元素
    for (Integer integer : treeSet) {
      System.out.println(integer);
    }
  }
}

十、Map 接口

1、接口

Map 是独立的接口。和 Collection 没有关系。
Map 中每个元素都是 Entry 类型,每个元素都包含 Key(键)和 Value(值)

2、继承关系

在这里插入图片描述

3、包含的API

在这里插入图片描述

十一、HashMap

1、介绍

HashMap 是对散列表的具体实现。
里面都包含 Key-Value 值。
在这里插入图片描述

2、代码演示

import java.util.HashMap;

public class TestHashMap {

    public static void main(String[] args) {
        HashMap<Integer, String> sites = new HashMap<>();
        sites.put(1, "Google");
        sites.put(2, "Runoob");
        sites.put(3, "Taobao");
        System.out.println(sites);
        //1.访问元素
        /*System.out.println(sites.get(2));*/
        //2.删除元素
        /*sites.remove(2);
        System.out.println(sites);*/
        //3.删除所有键值对
        /*sites.clear();
        System.out.println(sites);*/
        //4.计算大小
        /*System.out.println(sites.size());*/
        //5.迭代 HashMap
        /*for (Integer integer : sites.keySet()) {
            System.out.println("key:" + integer + "value" + sites.get(integer));
        }*/
        /*for (String value : sites.values()) {
            System.out.println(value);
        }*/
        //6.赋值一份 hashMap
        /*Object clone = sites.clone();
        System.out.println(clone);*/
        /*HashMap<Integer, String> clone = (HashMap<Integer, String>)sites.clone();
        System.out.println(clone);*/
        //7.检查 HashMap 是否为空
        /*boolean empty = sites.isEmpty();
        System.out.println(empty);*/
        //8.将所有键值对插入到 HashMap
        /*HashMap<Integer, String> site1 = new HashMap<>();
        site1.put(4, "Tom");
        site1.put(5, "Wiki");
        sites.putAll(site1);
        System.out.println(sites);*/
        //9.判断 key 是否存在,不存在则将键/值插入到 HashMap 中
        /*sites.putIfAbsent(2, "Wiki");
        sites.putIfAbsent(4, "Wiki");
        System.out.println(sites);*/
        //10.检查 hashMap 中是否存在 指定 key 对应的映射关系
        /*boolean b = sites.containsKey(2);
        System.out.println(b);*/
        //11.检查 hashMap 中是否存在 指定 value 对应的映射关系
        /*if (sites.containsValue("Taobao")) {
            System.out.println("Taobao存在于 sites 中。");
        }*/
        //12.替换 hashMap 中指定 key 对应的 value
        /*String wiki = sites.replace(2, "Wiki");
        System.out.println(wiki);
        System.out.println(sites);*/

        /*boolean replace = sites.replace(2, "Runoob", "Wiki");
        System.out.println(replace);
        System.out.println(sites);*/

        //13.将 hashMap 中所有映射关系替换成给定的函数所执行的结果
        /*sites.replaceAll((key, value) -> value.toUpperCase());*/
        /*System.out.println(sites);*/

        //14.获取指定的 key,不存在返回默认值
        /*String wiki = sites.getOrDefault(2, "Wiki");
        System.out.println(wiki);*/

        //15.forEach()方法的使用
        /*sites.forEach((key, value) -> {
            value = value + "--HAHA";
            System.out.println(key + "=" + value + "");
        });*/

        //16.返回映射中包含的映射的 set 视图
        /*System.out.println(sites.entrySet());*/

        //17.获取映射 中所有 key 组成的 set 视图
        /*System.out.println(sites.keySet());*/

        //18.获取映射 中所有 value 组成的 set 视图
        /*System.out.println(sites.values());*/

        //19.merge 先判断指定的 key 是否存在,如果不存在,则添加键值对到 hashMap 中
        /*String wiki = sites.merge(4, "Wiki", (oldVaule, newValue) -> oldVaule + newValue);
        System.out.println(wiki);
        System.out.println(sites);*/

        //20.compute() 方法对 hashMap 中指定的 key 的值进行重新计算
        /*String compute = sites.compute(3, (key, value) -> value + "HAHA");
        System.out.println(compute);
        System.out.println(sites);*/

        //21.对 hashMap 中指定的 key 值进行重新计算,如果不存在这个 key,则添加到 hashMap 中
        /*String s = sites.computeIfAbsent(4, key -> "Wiki");
        System.out.println(s);
        System.out.println(sites);*/

        //22.对 hashMap 中指定的 key 的值进行重新计算,前提 是该 key 存在于 hashMap 中
        String s = sites.computeIfPresent(3, (key, value) -> value + "HAHAHA");
        System.out.println(s);
        System.out.println(sites);
    }
}

十二、TreeMap

1、简介

红黑树的具体实现

2、代码实例

总体和 HashMap 使用非常类似

public class TestTreeMap {
  public static void main(String[] args) {
    Map<Integer, String> treeMap = new TreeMap<>();
    treeMap.put(2, "bb");
    treeMap.put(1, "aa");
    treeMap.put(3, "cc");
    for (Map.Entry<Integer, String> entry : treeMap.entrySet()) {
      System.out.println(entry.getKey() + ":" + entry.getValue());
    }
  }
}

十三、Iterator

1、简介

迭代器,是一个接口,每个集合中实现类都对 Iterator 提供了内部的实现。
通过 Iterator 可以实现遍历集合的效果。
存在意义:
隐藏集合实现细节,无论是哪种集合都是通过 Iterator 进行操作,而不是直接操作集合。通过一套 API 实现所有集合的变量。
可以在遍历时删除集合中的值。

2、实例化

每个实现类都提供了 .iterator();返回值就是迭代器对象。

public class TestIterator {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    //获取集合的迭代器
    Iterator<Integer> iterator = list.iterator();
    //.hasNext() 判断是否有下一个元素
    while (iterator.hasNext()) {
      //获取下一个元素
      Integer next = iterator.next();
      System.out.println(next);
    }
  }
}

3. ConcurrentModificationException

在循环遍历集合时,向集合中插入值或删除集合中值时会出现这个异常。

public class Test {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    for (Integer integer : list) {
      list.remove(integer);
    }
  }
}

异常截图:
在这里插入图片描述
为什么使用 for(int i = 0; i < list.size(); i++){} 时不出现这个异常?
因为这种循环其实是多次执行 get,调用 get() 方法时,集合 对其他元素删除 或新增是没有要求的。而增强 for 循环是把集合看作哟个整体,在遍历集合时,不允许对整个集合进行操作。

4、遍历集合时删除元素的内容

public class Test {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    list.add(2);
    list.add(3);
    //获取集合的迭代器
    Iterator<Integer> iterator = list.iterator();
    //.hasNext() 判断是否有下一个元素
    while (iterator.hasNext()) {
      //获取下一个元素
      Integer next = iterator.next();
      //删除当前元素
      iterator.remove();
    }
  }
}

十四、Collections

1、介绍

Collections 是一个工具类型,一个抓们操作集合的工具类。

2、代码示例

public class TestCollections {
  public static void main(String[] args) {
    List<Integer> list = new ArrayList<>();
    list.add(2);
    list.add(1);
    list.add(3);

    //将集合中的元素排序
    Collections.sort(list);

    for (Integer integer : list) {
      System.out.println(integer);
    }
    //将多个元素添加到集合中
    Collections.addAll(list, 4, 6, 5);

    //获取集合中最大值
    Integer max = Collections.max(list);
    //获取集合中最小值
    Integer min = Collections.min(list);
  }
}

十五、不定项参数

1、简介

不定项参数必须在方法定义时,最后一个方法参数。
调用包含不定项参数的方法时,不定项参数位置,可以传递 0 到 任意个指定类型的参数。
方法内部,把不定项参数当做 数组使用即可。

2、代码示例

public class TestArgs {
  public static void main(String[] args) {
    test("zs"); //没有传值, 数组长度为0
    test("ls", 1, 2, 3); //传值, 数组长度为3
  }

  public static void test(String name, int... i){
    System.out.println(i);
    System.out.println(Arrays.toString(i));
  }
}

相关文章:

  • Linux--文件系统
  • 第四章 结构化程序设计
  • 【数据挖掘】岭回归(Ridge Regression)和线性回归(Linear Regression)对比实验
  • TBE(TVM的扩展)
  • 滑动窗口滤波
  • OpenIPC开源FPV之Adaptive-Link日志分析
  • 【Linux操作系统】:信号
  • 【Java设计模式】第10章 外观模式讲解
  • C++进阶笔记第一篇:程序的内存模型
  • 简单回溯(组合力扣77)
  • OpenCV 图形API(22)矩阵操作
  • SAP Overview
  • 淘宝 API 高并发优化:突破 QPS 限制的分布式爬虫架构设计
  • java导入excel更新设备经纬度度数或者度分秒
  • UTF-8和GBK编码的区别和详细解释
  • Unity Input 2023 Release-Notes
  • 数据结构第六章(一) -图
  • Dynamics 365 Business Central VS Code AL 开发 多语言的支持
  • Linux系统远程操作和程序编译
  • Spring Boot 国际化配置项详解
  • 中国金茂新任命三名副总裁,撤销区域公司
  • 新买宝马竟是“维修车”,男子发视频维权被4S店索赔100万
  • 保证断电、碰撞等事故中车门系统能够开启!汽车车门把手将迎来强制性国家标准
  • 大四本科生已发14篇SCI论文?重庆大学:成立工作组核实
  • 万达电影:股东杭州臻希拟减持不超1.3927%公司股份
  • 特朗普政府拟终止太空污染研究,马斯克旗下太空公司将受益