Java中集合及其常用方法总结

本文介绍了Java集合框架的基础知识,包括Collection和Map两大接口的子类如ArrayList、HashSet以及它们的特点和常用API。讲解了集合的遍历方式,如迭代器、foreach循环和Lambda表达式,并探讨了底层数据结构如数组和链表。此外,还涉及了可变参数和Collections工具类的使用。
摘要由CSDN通过智能技术生成

一、集合的基本概述

集合是Java中存储对象数据的一种容器。

特点:①集合的大小不固定,启用后长度可以动态变化,集合中存储类型也可以选择不固定;②集合非常适合做元素的增删操作(有很多可以直接调用的API);③集合中只能存储引用类型数据,如果要存储基本类型数据可以选用包装类。

Q:集合中可以存储不同类型的元素,是创建一个集合之后,可以同时存储不同类型的元素吗?        A:是的。参见如下代码,其输出为:   [I'm String, 1, true]       

import java.util.ArrayList;
import java.util.Collection;
public class DifferentElementTest {
    public static void main(String[] args) {
        //集合中可以存储不同类型的元素,是创建一个集合之后,可以同时存储不同类型的元素吗?
        Collection set=new ArrayList();
        set.add("I'm String");
        set.add(1);
        set.add(true);
        //打印
        System.out.println(set);
    }
}

二、集合的体系结构

分为Collection单列集合Map双列集合

Collection单列集合:每个元素(数据)只包含一个值。                                                                        Map双列集合,每个元素包含两个值(键值对 (Key,Value))。

集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型。

三、Collection集合

Collection是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。

3.1 数据手册中罗列的所有接口及本文中主要概述的常用接口

数据手册中罗列的所有接口

我们主要概述的接口(图源黑马程序员)

3.2 Collection单列集合特点

3.2.1 List系列集合

添加的元素是有序、可重复有索引

3.2.2 Set系列集合

HashSet: 添加的元素是无序、不重复无索引

LinkedHashSet: 有序、不重复无索引

TreeSet:按照大小默认升序排序、不重复无索引

3.3Collection常用的API

public boolean add(E e);

public void clear();

public boolean remove(E e);

public boolean contains(Object obj);

public boolean isEmpty();

public int size();

public Object[] toArray();                                        //把集合中的元素,存储到数组中。

3.4 迭代方式&具体实现

3.4.1 迭代器及其常用方法

Collection集合获取迭代器:

Iterator<E> iterator(); //返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引

常用方法:

boolean hasNext();      //询问当前位置是否有元素存在,存在则返回true,反之false

E next();   //获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出越界

 具体实现:

输出为:How are you ? 

        //数据准备
        Collection arrayList=new ArrayList();
        arrayList.add("How");
        arrayList.add("are");
        arrayList.add("you");
        arrayList.add("?");
        //使用迭代器方法遍历并打印当前元素
        Iterator it=arrayList.iterator();
        while(it.hasNext()){
            System.out.print(it.next()+" ");
        }

3.4.2 foreach/增强for循环

既可以遍历集合也可以遍历数组,它是JDK5之后出现的,其内部原理是一个iterator迭代器,遍历集合相当于是迭代器的简化写法。只有实现了Iterable接口的类才可以使用迭代器和增强for,Collection接口已经实现了Iterable接口。

其格式:

for(元素数据类型   变量名 : 数组或者Collection集合){

        //在此处使用变量来完成自己所想的操作,变量对应的就是元素

}

注:如果使用的是idea编译器,可以通过输入  "集合名称.for" 来使用foreach框架

具体实现:

输出为:How~are~you~?~

        //数据准备
        Collection arrayList=new ArrayList();
        arrayList.add("How");
        arrayList.add("are");
        arrayList.add("you");
        arrayList.add("?");
        //使用foreach/增强for循环遍历并打印当前元素
        for (Object o : arrayList) {
            System.out.print(o+"~");
        }

3.4.3 lambda表达式

得益于JDK8开始的新技术Lambda表达式(匿名函数,即没有函数名的函数),提供了一种更简单、更直接的遍历集合的方式。

Collection结合Lambda遍历的API

default void forEach(Consumer<? superT>action):    //结合Lambda遍历集合

 具体实现:

输出为:   How--are--you--?--

        //数据准备
        Collection arrayList=new ArrayList();
        arrayList.add("How");
        arrayList.add("are");
        arrayList.add("you");
        arrayList.add("?");
        //使用Lambda方式遍历并打印当前元素
        arrayList.forEach(new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.print(o+"--");
            }
        });

 还有简化匿名内部类的写法

        //数据准备
        Collection arrayList=new ArrayList();
        arrayList.add("How");
        arrayList.add("are");
        arrayList.add("you");
        arrayList.add("?");
        //使用Lambda方式遍历并打印当前元素
        arrayList.forEach(o-> {
                System.out.print(o+"--");
        });

3.5 List系列集合

3.5.1 集合特点详细解释

ArrayList、LinkedList:有序、可重复、有索引。

有序:存储和取出的元素顺序一致。

有索引:可以通过索引操作元素。

可重复:存储的元素可以重复

3.5.2 List集合特有API

void add(int index,E element)         在集合中的指定位置插入指定的元素

E remove(int index)                        删除指定索引处的元素,返回被删除的元素

E set(int index,E element)              修改指定索引处的元素,返回被修改的元素

E get(int index)                               返回指定索引处的元素

3.5.3 List集合的遍历方式

比之前3.4中所述的方式多了一种:for循环(因为List集合是有索引的)           

输出为:How are you ?                                                                             

        List<String> list=new LinkedList();
        list.add("How");
        list.add("are");
        list.add("you");
        list.add("?");
        for (int i = 0; i < list.size(); i++) {
            String s=list.get(i);
            System.out.print(s+" ");
        }

3.5.4 ArrayList集合的底层原理

ArrayList底层是基于数组实现的,它在内存中使用一个连续的数组来存储元素:根据索引定位元素快,增删需要做元素的移位操作。
第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组。当容量满的时候,自动扩容。

当进行查询操作时,只需要通过下标直接访问相应的数组元素即可,这个过程的时间复杂度是 O(1),即常量时间。而增加或删除元素时,需要移动后面的元素以保持数组的连续性,这个过程的时间复杂度是 O(n),即线性时间,其中 n 是数组的长度。因此,当元素数量很大时,增加或删除元素的时间复杂度将会很高。

此外,由于 ArrayList 内部是基于数组实现的,所以在插入或删除元素时需要进行数组的复制或移动操作,这会带来额外的空间和时间成本。而且,当 ArrayList 中的元素数量达到一定程度时,可能需要扩容数组,这也会导致额外的时间和空间成本。

3.5.5 LinkedList集合的底层原理

底层数据结构是双链表,查询慢,但是首尾操作的速度是极快的。

3.5.5 LinkedList集合的特有功能

public void addFirst(E e)                                 在该列表开头插入指定的元素
public void addLast(E e)                                 将指定的元素追加到此列表的末尾
public E getFirst( )                                          返回此列表的第一个元素
public E getLast( )                                          返回此列表的最后一个元素
public E removeFirst( )                                   从此列表中删除并返回第一个元素
public E removeLast( )                                   从此列表中删除并返回最后一个元素

3.6 Set系列集合

3.6.1 集合特点详细解释

HashSet:无序、不重复、无索引
LinkedHashSet:有序、不重复、无索引
TreeSet:排序、不重复、无索引

无序:存取顺序不一样
有序:存取顺序一样
排序:会对插入的元素进行排序
不重复:可以去除重复的元素
无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素。

3.6.2 集合特有API

3.6.3 List集合的遍历方式

3.6.4 HashSet集合的底层原理及去重原理分析

HashSet集合底层采取哈希表存储的数据。哈希表是一种对于增删改查数据性能都比较好的结构。

哈希表的组成(在JDK8之前,底层采用数组+链表;JDK8之后,底层采用数组+链表+红黑树)

哈希值:是JDK根据对象的地址,按照某种规则算出来的int类型的数值。
              public int hashCode():返回对象的哈希值
              对象的哈希值特点:①同一个对象多次调用hashCode()方法返回的哈希值是相同的;
                                              ②默认情况下,不同对象的哈希值是不同的。

                   图源:黑马程序员

                   图源:黑马程序员

                   图源:黑马程序员

                 图源:与ChatGPT的对话

3.6.5 LinkedHashSet集合的底层原理

                图源:黑马程序员

3.6.6 TreeSet集合的底层原理

底层基于TreeMap实现,基于红黑树实现排序,增删改查性能较好。

                 图源:黑马程序员

 自定义排序规则:

第一种方式:让自定义的类(如学生类)实现Comparable接口重写里面的compareTo方法来定制比较规则;


第二种方式:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来定制比较规则。

 

 以上两种方式中,关于返回值的规则:
如果认为第一个元素比第二个元素大返回正整数即可。(升序)
如果认为第一个元素比第二个元素小返回负整数即可。(降序)
如果认为第一个元素等于第二个元素返回0即可,此时TreeSet集合只会保留一个元素,认为两者重复。
注:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序。

四、Map集合

Map是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。

4.1 数据手册中罗列的所有接口及本文中主要概述的常用接口

我们主要概述的接口如下【图源黑马程序员】

4.2 集合体系特点 

Map集合的特点都是由键决定的。
Map集合的键是无序,不重复,无索引的,值不做要求(可以重复)。
Map集合后面重复的键对应的值会覆盖前面重复键的值。
Map集合的键值对都可以为null。

Map集合实现类特点:
HashMap:键是无序的,不重复,无索引,值不做要求。(与Map体系一致)
LinkedHashMap:键有序,不重复,无索引,值不做要求。
TreeMap:键排序,不重复,无索引,值不做要求。

4.3 Map常用的API

方法名称说明
V put( K  Key, V  Value )添加元素
V remove( Object Key )        根据键删除键值对元素
void clear( )移除所有的键值对元素
boolean containsKey(Object  Key)判断集合是否包含指定的键
boolean containsValue(Object value)判断集合是否包含指定的值
boolean isEmpty( )判断集合是否为空
int size( )        集合的长度,也就是集合中键值对的个数

获取键的集合&获取值的集合

public static void main(String[] args) {
        Map<String,Integer> map1=new HashMap<>();
        map1.put("hello",1);
        map1.put("hi",2);
        map1.put("bye~",3);
        //获取键的集合
        Set<String> keys=map1.keySet();
        System.out.println(keys);
        //获取值的集合
        //由于value可重复,所以我们不能使用Set的集合
        Collection<Integer> values=map1.values();
        System.out.println(values);
    }

合并其他map集合:

   public static void main(String[] args) {
        //map1
        Map<String,Integer> map1=new HashMap<>();
        map1.put("hello1",1);
        map1.put("hi1",2);
        map1.put("bye1~",3);
        //map2
        Map<String,Integer> map2=new HashMap<>();
        map2.put("hello2",1);
        map2.put("hi2",2);
        map2.put("bye2~",3);
        //整合到一块
        map1.putAll(map2);
        //打印输出
        System.out.println(map1);
        //输出结果为:{hi2=2, hi1=2, hello1=1, bye1~=3, bye2~=3, hello2=1}
}

4.4 遍历方式&具体实现

4.4.1遍历方式一:键找值

public static void main(String[] args) {
        //1.创建一个Map集合对象
        Map<String,Integer> maps=new HashMap<>();
        maps.put("娃娃",30);
        maps.put("粑粑",20);
        maps.put("蕾蕾",10);
        maps.put("花花",40);
        //使用键找值方式遍历
        //1.首先将Map集合的键转换成Set集合
        Set<String> keys = maps.keySet();
        //2.开始遍历
        for (String key:keys){
            int value=maps.get(key);
            System.out.println(key+"===>"+value);
        }
}

4.4.2遍历方式二:键值对

public static void main(String[] args) {
        //1.创建一个Map集合对象
        Map<String,Integer> maps=new HashMap<>();
        maps.put("娃娃",30);
        maps.put("粑粑",20);
        maps.put("蕾蕾",10);
        maps.put("花花",40);
        System.out.println(maps);
        //使用键值对遍历
        //1.首先将Map集合转换成Set集合
        Set<Map.Entry<String, Integer>> entries = maps.entrySet();
        System.out.println(entries);
        //2.开始遍历
        for (Map.Entry<String, Integer> entry:entries){
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
}

4.4.3遍历方式三:Lambda表达式

public static void main(String[] args) {
        //1.创建一个Map集合对象
        Map<String,Integer> maps=new HashMap<>();
        maps.put("娃娃",30);
        maps.put("粑粑",20);
        maps.put("蕾蕾",10);
        maps.put("花花",40);
        System.out.println(maps);
        //使用Lambda表达式遍历
        //1.
        maps.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String key, Integer value) {
                System.out.println(key+"===>"+value);
            }
        });
        //2.
        maps.forEach((k,v)-> {
            System.out.println(k+"=====>"+v);
        });
    }
}

4.5 HashMap集合

特点:与Map体系结构一致,特点由键决定,无序,无重复,无索引。

HashMap跟HashSet底层原理是一模一样的,都是哈希表结构,只是HashMap的每个元素包含两个值而已。

实际上,Set系列结合的底层就是Map实现的,只是Set集合中的元素只要键对象,不要值对象。

4.6 LinkedHashMap集合

特点:特点由键决定,有序(存储和取出的元素顺序一致),无重复,无索引。
原理:底层数据结构是哈希表,只是每个键值对元素又额外多了一个双链表的机制记录存储的顺序。

4.7 TreeMap集合

特点:特点由键决定,不重复,无索引,可排序(按照键数据的大小默认升序排序,也可以将键按照指定的规则进行排序)。
TreeMap和TreeSet的底层原理是一样的。

五、可变参数和工具类Collections

5.1 可变参数

可变参数在形参中可以接收多个数据,其格式为

数据类型...参数名称

可变参数的作用:传输参数非常灵活,方便。可以不传输,或传输1个或者多个,也可以传输一个数组。其在方法内部本质上就是一个数组。

可变参数的注意事项:1.一个形参列表中可变参数只能有一个;可变参数必须放在形参列表的后面。

例如:打印n个数,

public class VariableParameter {
    public static void main(String[] args) {
        calculate(3,1,2,3);
    }
    public static void calculate(int n,int...var){
        for(int i=0;i<n;i++){
            System.out.print(var[i]+" ");
        }
    }
}

5.2工具类Collections

5.2.1 给集合对象批量添加元素

Collections.addAll(collectionName,data_1,...,data_n);

    public static void main(String[] args) {
        List<Integer> order=new ArrayList<>();
        order.add(1);
        order.add(2);
        order.add(3);
        order.add(4);
        System.out.println(order);//[1, 2, 3, 4]
        Collections.addAll(order,4,5,6,7);
        System.out.println(order);//[1, 2, 3, 4, 4, 5, 6, 7]
    }

5.2.2 打乱list集合顺序

Collections.shuffle( listName); 

    public static void main(String[] args) {
        List<Integer> order=new ArrayList<>();
        Collections.addAll(order,1,2,3,4);
        System.out.println(order);//[1, 2, 3, 4]
        Collections.shuffle(order);
        System.out.println(order);//[2, 3, 4, 1]
    }

 5.2.3排序(使用范围:只能用于List集合的排序)

public static <T> void sort(List<T> list)      //将集合中元素按照默认规则排序,本方式不可                                                                        //以直接对自定义类型的List集合排序,除非                                                                              //自定义类型实现了比较规则Comparable接口。

public static <T> void sort(List<T> list,Comparator<? super T> c)

                                                                 //将集合中元素按照指定规则排序

    //按照默认规则进行排序
    public static void main(String[] args) {
        List<Integer> order=new ArrayList<>();
        Collections.addAll(order,1,2,3,4);
        Collections.shuffle(order);
        Collections.sort(order);
        System.out.println(order);  //[1, 2, 3, 4]
    }
//创建学生类,实现Comparable接口
public class Student implements Comparable<Student>{
    public String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


    @Override
    public int compareTo(Student o) {
        //升序:this.age-o.age
        //降序:o.age-this.age
        return o.getAge()-this.age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
//main中调用sort函数,查看是否为降序输出
    public static void main(String[] args) {
        List<Student> ls=new ArrayList<>();
        Student s1=new Student("a",18);
        Student s2=new Student("b",19);
        Student s3=new Student("c",20);
        Collections.addAll(ls,s1,s2,s3);
        Collections.sort(ls);
        System.out.println(ls);//[Student{name='c', age=20}, Student{name='b', age=19}, Student{name='a', age=18}]
    }
    //by using Comparator
    public static void main(String[] args) {
        List<Integer> order=new ArrayList<>();
        Collections.addAll(order,1,2,3,4);
        Collections.shuffle(order);
        Collections.sort(order, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
        System.out.println(order);  //[4, 3, 2, 1]
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值