java集合框架

java集合框架

前言:本节我们来学习java集合框架

1.0 什么是集合

集合便是对象的容器,定义了多个对象进行操作的常用方法

集合和数组的区别:

1 数组长度固定,集合长度不固定

2 数组可以存储基本类型和引用类型,集合只能存储引用类型。

我们在使用集合时,需要导入java.utill的所有内容

集合分为单列集合和双列结合,单列集合一次只能添加一个元素,而双列集合一次可以添加一对

元素,我们先来学习单列集合,即Collection体系

1.1 Collection体系集合

collection是该体系的根节点,它的子节点由List和Set

List接口的特点:有序,有下标,元素可重复,有序,即存储顺序就是元素插入到list中的顺序,

且可以根据下标来根据顺序进行访问。

Set接口的特点:无序,无下标,元素不能重复。

上面的这三者是接口,规定了要实现的内容,具体的内容必须由接口的子类来实现,所以上面这

三者是无法实例化的。我们来看一下正Collection体系的图:

1.2 Collection父接口

该接口的方法:

1. 添加功能
    boolean add(E e)
        添加一个元素
    boolean addAll(Collection c)  
        添加一批元素
2. 删除功能
   boolean remove(Object o)
       删除一个元素
3. 判断功能
   boolean contains(Object o)
       判断集合是否包含指定的元素
   boolean isEmpty()  
       判断集合是否为空(集合中没有元素)
4. 获取功能
   int size()  
      获取集合的长度
5. 转换功能
   Object[] toArray()
       把集合转换为数组

还有其他方法请查看api

需要注意的是,collection是接口,我们无法直接实例化,可以借助指向其子类的对象来实例

化,此时我们称其为实现类这就体现了java的多态特点,比如我们可以指向ArrayList,由于下

标是在其实现类中实现的,所以不能直接使用下标进行访问,如果我们利用类型转化将其转化

为ArrayList,就可以使用下标对其进行访问,由之前多态的学习我们可以知道,对于在子类中

被重载的方法,如果我们用父类执行子类的对象,那么这些方法可以在父类中使用,对于接口

也是这样。

对于集合的遍历,我们可以使用增强for,也可以使用迭代器,java中提供了迭代器接口,由不同

的类进行了实现。迭代器接口定义了三个方法 hasNext() Next() remove()

第一个方法是判断集合中是否存在下一个元素,第二个方法是将引用转向下一个元素,第三个

方法是用于迭代器中的对集合中元素进行删除的方法。

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        Collection collection = new ArrayList<>();
        collection.add("1");
        collection.add("2");
        System.out.println(collection.size());
        collection.remove("1");
        collection.add("dada");
        System.out.println(collection);
        // 增强for
        for (Object o : collection) {
            System.out.println(o);
        }
        // 迭代器
        Iterator i = collection.iterator();
        while (i.hasNext()) {
            System.out.println(i.next());
            i.remove();
        }

    }
}

i.remove()是删除迭代器当前指向的函数。不能直接使用collection.remove(i)

我们还需要注意的是,当我们使用增强类对集合进行遍历时,对于上面的o的类型只能是

object,不能是集合中存储数据的类型, 如果我们想要使用集合中比如对象的方法,需要使用到

强制类型转化

举个列子

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        var s1 = new Dog("john");
        var s2 = new Dog("jack");
        Collection c = new ArrayList();
        c.add(s1);
        c.add(s2);
        for (Object i : c) {
            Dog d = (Dog) i;
            d.makeSound();
        }

    }
}

还需要记住,无论是添加还是删除,直接操作的都是引用对应的地址,我们删除并非是将该元素

从地址中删除,而是删除引用对该地址的指向, 实际还是会在存储空间中存储该元素,因此我

们知道,在使用删除方法时并不是按值进行删除的,而是按地址进行删除的,我们如果删除一个

和集合中某元素的值相同,但地址不同的对象,实际上并不会删除。

1.3 List接口

List接口是Collection接口的子接口,特点有:

有序,有下标,元素可以重复

常见方法:

indexOf() 返回此列表中第一次出现的指定元素的索引,如果不包含,则返回-1

add(int index, Object o) 通过此方法,我们可以在对应下标处添加元素。

add(int index,Collection c ) 将一个集合中的元素添加到此集合中的index位置

Object get(int index)返回指定位置的元素

List subList(int fromIndex,int toIndex)

返回两个位置之间的元素,以List形式返回。

两个这个区间任然为左闭右开

除了这些方法,其父接口Collection的所有方法它也具有,可以使用

下面是一个实际使用 subListd的例子

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        for (int i = 1; i <= 4; i++) {
            list.add(i);
        }
        List a = list.subList(1, 3);
        for (Object object : a) {
            System.out.println(object);
        }
    }
}

我们如果想要根据下标访问对应的元素,需要用到get(int intdex)方法。还需要注意的是,

如果我们按下标添加,必须要根据顺序从下标0从小到大进行添加,如果我们想要对某个下标的

值进行更改,不能超出当前最大下标,原因是list接口的实现类ArrayList是动态内存,是根据我

们目前的使用去不断扩大内存的,所以我们如果索引指向没有扩大的下标是无法进行插入和访问

的,还需要注意的是,当我们使用add(Object o)时,是将元素加到最后,当我们add(int

index,Object o) 时,是将当前坐标以及后面的所有的元素往后移一格,然后再将插入的元

素插入对应坐标

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(0, 1);
        System.out.println(list.get(0));
    }
}

remove(int index) 根据脚标删除元素

remove(Object o) 根据值删除元素,删除第一次出现的元素

我们需要注意的是,当list的元素全是数字类型时,我们使用remove(Object o) 是不行的,因

为此时o为数字,会默认将其认为是下标,而不是具体的值。为什么会这样呢?因为集合是不能

添加基本类型的,而数字正是基本类型,当我们将数字加入集合时有一个自动装箱过程,将其转

化为包装类 我们来看一下其解释:

自动装箱(autoboxing)是Java5中引入的一项功能,它指的是Java编译器会自动将基本数据类

型值转换为对应的包装器类型对象的过程。例如,将int类型的变量转换为Integer对象,将

boolean类型的变量转换为Boolean对象。

那我们此时如果想要根据数字的值来进行删除,应该怎么做呢?既然基本类型在存储是会自动装

箱,将其转换为对象,那我们直接将数字转化为对象再删除即可。

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        for (int i = 0; i <= 3; i++) {
            list.add(i, i);
        }
        list.add(3, 11);
        // list.remove(11); 这种方式不行
        list.remove((Object) 11);
        //list.remove((Integer) 11); 这种也可以
        //list.remove(new Integer(11)); 这种也可以
        for (Object object : list) {
            System.out.println(object);
        }
    }
}

换成字符串就正常了。

List的遍历方式有很多,for增强for迭代器 迭代器除了上面的普通迭代器,还有列表迭代

for利用的是get方法访问角标,增强for和迭代器访问和Collection相同

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        for (int i = 0; i <= 3; i++) {
            list.add(i, i);
        }
        Iterator it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}

我们再来看看系列表迭代器 如何使用

该迭代器的功能要多于普通的迭代器,它允许我们选择向前或者向后遍历,允许我们添加,删

除,修改元素

常用方法(忽略了与普通迭代器相同的部分):

nextIndex() 返回下一个元素的角标

hasPreviouse()hasNext()类似,只不过是判断上一个元素是否存在

previousIndex()返回上一个元素的角标

previous()将引用指向上一个元素

set() 将某位置的元素进行替换

add() 我们已知在使用普通迭代器时,是不能增加元素的,但对于系列表迭代器的add方法则是

可以加入元素的。

import java.util.*;

import com.corejava.test.*;

public class Main {
    public static void main(String[] args) {
        List list = new ArrayList();
        for (int i = 0; i <= 3; i++) {
            list.add(i, i);
        }
        ListIterator it = list.listIterator();
        while (it.hasNext()) {
            System.out.println(it.nextIndex() + ":" + it.next());
        }
        System.out.println("-------------------");
        while (it.hasPrevious()) {
            System.out.println(it.previousIndex() + ":" + it.previous());
        }
    }
}

1.4 List实现类

ArryList

由数组结构实现,查询块,增删慢。

JDK1.2版本,运行效率快,线程不安全

Vector

由数组结构实现,查询块,增删慢。

JDK1.0版本,运行效率慢,线程安全

LinkedList

链表结构实现,增删快,查询慢。

1.5 Arraylist

Arraylist的存储结构为数组

查找遍历速度快,增删速度慢,可以通过下标访问

1.6 Lambda表达式

我们可以通过foreach遍历集合元素,而Lambda则是通过对foreach的省略达到相同效果

import java.util.*;
import java.util.function.Consumer;

import com.corejava.test.*;


public class Main {
    public static void test() {
        System.out.println(111);
    }
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.forEach(new Consumer<String>() {
            @Override
            public void accept(String o) {
                System.out.println(o);
            }
        });
    }
}

在这里用到了匿名内部类传递给foreach,其中Consumer是一个接口,其中定义了accept函数来

接受输入的数据,后面的String声明了输入的数据类型,o,就是获取的集合中的一个个元素,通

过此方式实现对集合的遍历。

我们如果使用Lambda表达式,可以简化为:

import java.awt.print.Printable;
import java.util.*;
import java.util.function.Consumer;

import com.corejava.test.*;


public class Main {
    public static void test() {
        System.out.println(111);
    }
    public static void printThing(Printable thing){
        thing.print();
    }
    public static void main(String[] args) {
        Dog dog= new Dog("jack");
        dog.sleep();
        ArrayList<String> list = new ArrayList<String>();
        list.add("1");
        list.add("2");
        list.forEach(s -> System.out.println(s));
    }
}

1.7 泛型的特点

泛型的第一个特点为泛型不具备继承性,数据具备继承性

import java.util.ArrayList;

public class MyArrayList{
    public static void main(String[] args) {
    //    ArrayList<GF> list1=new ArrayList<>();
          ArrayList<String> list=new ArrayList<>();
          ArrayList<Object> list1=list;
    }
}

这样的写法是不行的,因为泛型不具备继承性,所以我们不能用指定存储类型为Object的ArrayList引用指向指定

类型为String的对象。

因此,下面这种写法也是不行的

import java.util.ArrayList;

public class MyArrayList{
    public static void main(String[] args) {
        ArrayList<Car> cars = new ArrayList<>();
        cars.add(new Car());
        method(cars);
        ArrayList<Su7> su7s = new ArrayList<>();
        method(su7s);
    }
    public static void method(ArrayList<Car> c){}

}
class  Car {}
class Su7 extends Car{}

我们的method函数指定的接受数据类型为ArrayList,即使在继承关系上Su7为Car的子类,也无法接受该

那如果我们的函数需要接收不同类型的泛型呢?

这时候就需要使用通配符了

import java.util.ArrayList;

public class MyArrayList{
    public static void main(String[] args) {
        ArrayList<Car> cars = new ArrayList<>();
        cars.add(new Car());
        method(cars);
        ArrayList<Su7> su7s = new ArrayList<>();
        method(su7s);
    }
    public static void method(ArrayList<?> c){}

}
class  Car {}
class Su7 extends Car{}

我们使用通配符?让所有类型的泛型都可以被接受

但是如果这样写那么所有的泛型类型都可以传递给函数,如果我们对传入的泛型类型又有了要求,只要某类和其子

类的泛型,这样不久又不能实现了吗?想要实现这个目的,我们对通配符?进行约束

? extends Car 这种写法要求传递的泛型必须是Car及其子类

? super Car 这种写法要求传递的泛型必须是Car及其父类

也就是说

import java.util.ArrayList;

public class MyArrayList{
    public static void main(String[] args) {
        ArrayList<Car> cars = new ArrayList<>();
        cars.add(new Car());
        method(cars);
        ArrayList<Su7> su7s = new ArrayList<>();
        method(su7s);
    }
    public static void method(ArrayList<? extends Car> c){}

}
class  Car {}
class Su7 extends Car{}

但是数据具有继承性,也就是说下面这样写是可以的

import java.util.ArrayList;

public class MyArrayList{
    public static void main(String[] args) {
    //    ArrayList<GF> list1=new ArrayList<>();
          ArrayList<String> list=new ArrayList<>();
          ArrayList<Object> list1=new ArrayList<>();
          list1.add("Hello");
    }
}

1.8 SET集合概述

上面我们已经基本了解了List集合,接下来我们来了解Set集合

Set系列集合特点:无序,不重复,无索引

HashSet:无序,不重复,无索引

LinkedHashSet: 有序,不重复,五索引

TreeSet :排序,不重复,无索引

先看一下简单演示

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class CollectionTest {
    public static void main(String[] args) {
        Set<String> set=new HashSet<>();
        set.add("Hello");
        set.add("World");
        set.add("Java");
        System.out.println(set);//无序
        Set<String> set1=new LinkedHashSet<>();
        set1.add("Hello");
        set1.add("World");
        set1.add("Java");
        System.out.println(set1);//有序
    }
}

输出为:

[Java, Hello, World]
[Hello, World, Java]

我们发现HashSet没有按我们的加入顺序显示,而LinkedHashSet则根据我们添加的顺序来进行输出

1.9 HashSet

Set容器的底层是通过哈希表实现的,底层有自动扩容的功能,当哈希表被填到一定程度时会自动将哈希表下挂的

链表转化为红黑树

对于对象来说,两个对象如果内容一样,默认情况下hash值是不一样的,但我们需要哈希值相同,并且使用

equals函数进行比较时要返回true,此时就需要我们重载hashCode方法和equals方法。

我们要实现对象去重的话就需要重载这两个方法

2.0 LinkedHashSet

LinkedHashSet和HashSet类似,同样是基于哈希表实现的,不过额外多了一个双链表去记载前后

元素的位置,从而实现对添加数据的顺序的记载,通过牺牲内存来实现功能

2.1 TreeSet

TreeSet相比其的set容器最大的区别就是在于其内部元素是有序的,默认为升序排序

对于数值类型可以自动排,对于字符串类型,可以用字典序排,对于对象,实现TreeSet的排序有两种方法

第一种是让自定义类实现Comparable接口,重写里面的compareTo方法来指定比较规则

第二种是直接调用TreeSet集合的有参构造器,传递一个比较器对象来传入比较规则

import org.w3c.dom.ls.LSOutput;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

public class CollectionTest {
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(new Student("Tom", 20));
        treeSet.add(new Student("Jerry", 22));
        treeSet.add(new Student("Jack", 21));
        for(Student i :treeSet){
            System.out.println(i);
        }
    }
}
class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString (){
        return "姓名"+name+"年龄:"+age;
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;// 按年龄升序
    }
}

这是实现方法1的有序排序

import org.w3c.dom.ls.LSOutput;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

public class CollectionTest {
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet<>((o1,o2)->o1.getAge()-o2.getAge());
        treeSet.add(new Student("Tom", 20));
        treeSet.add(new Student("Jerry", 22));
        treeSet.add(new Student("Jack", 21));
        for(Student i :treeSet){
            System.out.println(i);
        }
    }
}
class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public int getAge(){
        return  age;
    }
    @Override
    public String toString (){
        return "姓名"+name+"年龄:"+age;
    }

    @Override
    public int compareTo(Student o) {
        return this.age - o.age;// 按年龄升序
    }
}

这是第二种方式实现的排序。

2.2 可变参数

可变参数是一种特殊形参,定义在方法,构造器的形参列表里,格式是:数据类型...参数名称

其作用是当传递给函数的参数的数量不确定时,使用可变参数去解决该问题,可变参数可以接受不定数量的参数

在函数的内部,其就相当于一个数组,所以其可以使用下标进行访问,还可以通过增强for等方式进行访问

import org.w3c.dom.ls.LSOutput;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

public class CollectionTest {
    public static void main(String[] args) {
        sum(1,2,3,4,5);
    }
    public static void sum(int... nums){
        System.out.println(nums[0]);
        for(int i:nums){
            System.out.println(i);
        }
    }

}

注意:可变参数在形参列表中只能出现一个

​ 可变参数只能放在形参列表的最后

2.3 Collections工具类

Collection提供了不少的方法

addAll 该方法用来给集合一次性添加多个元素,用法为

import org.w3c.dom.ls.LSOutput;

import java.util.*;

public class CollectionTest {
    public static void main(String[] args) {
        sum(1,2,3,4,5);
    }
    public static void sum(int... nums){
        List<String>  studentList =new ArrayList<>();
        Collections.addAll(studentList,"1","2 ","3");
        System.out.println(studentList);
    }

}

输出结果为:

[1, 2 , 3]

可见传入的第二个参数为可变参数

shuffle

该方法用来打乱集合中元素的位置

import org.w3c.dom.ls.LSOutput;

import java.util.*;

public class CollectionTest {
    public static void main(String[] args) {
        sum(1,2,3,4,5);
    }
    public static void sum(int... nums){
        List<String>  studentList =new ArrayList<>();
        Collections.addAll(studentList,"1","2 ","3");
        System.out.println(studentList);
        Collections.shuffle(studentList);
        System.out.println(studentList);
    }

}

class Student {
    private int age;
    private String name;
    public int getAge(){
        return age;
    }
}

每次运行后打乱的结果都可能不同,不过该方法只支持打乱list集合的顺序,不能打乱

sort

该方法实现了集合内部的排序,对于基本类型可以自动升序排序,对于对象类型则需要指明排序规则,和之前一样

有两种方法指定排序规则,我就不多说了

import org.w3c.dom.ls.LSOutput;

import java.util.*;

public class CollectionTest {
    public static void main(String[] args) {
        sum(1,2,3,4,5);
    }
    public static void sum(int... nums){
        List<String>  studentList =new ArrayList<>();
        Collections.addAll(studentList,"1","2 ","3");
        System.out.println(studentList);
        Collections.shuffle(studentList);
        System.out.println(studentList);
        Collections.sort(studentList);
        System.out.println(studentList);
    }

}

class Student {
    private int age;
    private String name;
    public int getAge(){
        return age;
    }
}

2.4 MAP集合

上面的所有的集合都属于Collection集合,而map集合则属于另一个体系,collection集合属于单列集合,map属

于双列集合,或者说是键值对集合。在项目中如果需要存储一一对应的数据,就需要使用键值对区存储了。

同样MAP是一个接口,使用时需要实现类,常见的实现类有TreeMap HasMap LinkedHash

MAP集合中键不能重复,值不能重复。

其实set集合的底层就是基于Map,只不过只有键不需要值

HasMap:无序不重复,无索引

LinkedHashMap :有序,不重复,无索引

TreeMap 按大小排序,默认升序,不重复,无索引。

先看一下一个简单应用:

import java.util.HashMap;
import java.util.Map;

public class MyMap {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("key1",1);
        map.put("key2",2);
        map.put("key3",3);
        map.put("key5",4);
        map.put("key4",5);
        System.out.println(map);
    }
}

输出为:

{key1=1, key2=2, key5=4, key3=3, key4=5}

当出现重复的键时,后来的键会被前面的键所覆盖。null可以作为键也可以作为值

2.5 MAP常用方法

import java.util.*;

public class MyMap {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("key1",1);//添加键和值
        map.put("key2",2);
        map.put("key3",3);
        map.put("key5",4);
        map.put("key4",5);
        System.out.println(map.size());
        //size获得集合大小
        //map.clear();//清除集合元素
        System.out.println(map);
        System.out.println(map.get("key1"));
        //get方法用来根据键取数据
        System.out.println(map.remove("key1"));
        //用于根据键删除值,返回的为删除丶值
        System.out.println(map);
        //此时key1对应的已经没有了
        System.out.println(map.containsKey("key1"));
        //输出false,该方法用来判断是否存在一个键
        System.out.println(map.containsValue(2));
        // 输出true 该方法用来判断是否存在某个值
        Set<String> set=map.keySet();
        System.out.println(set);
        //该方法将所有的键放在Set集合中给出
        Collection<Integer> list=map.values();
        System.out.println(list);
        //同样,该方法会返回所有的值,不过由于会重复,所以返回的是一个Collection对象
        
    }
}

上面就是常见集合和用法

2.6 mpa集合的遍历

第一种遍历方法为键找值

import java.util.*;

public class MyMap {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("key1",1);//添加键和值
        map.put("key2",2);
        map.put("key3",3);
        map.put("key5",4);
        map.put("key4",5);
        Set<String> set= map.keySet();
        for(String key:set){
            int values=map.get(key);
            System.out.println(values);
        }
    }
}

第二种遍历方式为键值对方式

方法就是将map中的键和值转为Entry对象后加到set集合中

import java.util.*;

public class MyMap {
    public static void main(String[] args) {
        Map<String,Integer> map=new HashMap<>();
        map.put("key1",1);//添加键和值
        map.put("key2",2);
        map.put("key3",3);
        map.put("key5",4);
        map.put("key4",5);
        Set<Map.Entry<String,Integer>> entries=map.entrySet();
        for(Map.Entry<String,Integer> keyValue:entries){
            System.out.println(keyValue.getKey()+":"+keyValue.getValue());
        }
    }
}

第三种方式是使用lambda表达式去遍历

先看最基础的:

import java.util.*;
import java.util.function.BiConsumer;

public class MyMap {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("key1", 1);//添加键和值
        map.put("key2", 2);
        map.put("key3", 3);
        map.put("key5", 4);
        map.put("key4", 5);
    map.forEach(new BiConsumer<String, Integer>() {
        @Override
        public void accept(String s, Integer integer) {
            System.out.println(s+":"+integer);
        }
    });
    }
}

下面是简化后的

import java.util.*;
import java.util.function.BiConsumer;

public class MyMap {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("key1", 1);//添加键和值
        map.put("key2", 2);
        map.put("key3", 3);
        map.put("key5", 4);
        map.put("key4", 5);
    map.forEach((s1,s2)-> System.out.println(s1+":"+s2));
    }
}

来看个统计景区投票人数的案例:

import java.util.*;
import java.util.function.BiConsumer;

public class MyMap {
    public static void main(String[] args) {
        Map<String, Integer> choice = new HashMap<>();
        String[] list={"泰山","华山","长白山","华山","武当山","泰山","华山"};
        for(int i=0;i<7;i++){
            String place =list[i];
            if(choice.containsKey(place)){
                choice.put(place,choice.get(place)+1);
            }
            else {
                choice.put(place,1);
            }
        }
        choice.forEach((place ,times)-> System.out.println(place+"票数:"+times));

    }
}

2.7 HashMap

和HashSet的底层相同,都是哈希表实现的,根据entry对象的键进行哈希后的哈希值进行存储,如果长度超过8,

数组长度超过64会转化为哈希树

HashMap的键无序不重复无索引,跟HashSet一样,如果自定定义对象想要根据内容来去重,则需要重写

HashCode和equals方法

但当我们使用lombok时,自动会重写这几个方法,所以不需要我们重写了

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Movie {
    private String name;
    private Double score;
    private String actor;
}

2.8 LinkedHashMap

同样也是使用哈希表存数据,只不过会添加一个双链表存储存志的先后顺序

2.9 TreeMap

提供根据键排序

对于自定义对象重写排序规则同样有两种方式:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.*;
import java.util.function.BiConsumer;

public class MyMap {
    public static void main(String[] args) {
        Map<Movie,String> movieMap=new TreeMap<>((o1,o2)-> o1.compareTo(o2));

    }
}

在定义时写入

或者

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Comparator;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Movie implements Comparable<Movie> {
    @Override
    public int compareTo(Movie o) {
        return Double.compare(this.score,o.score);
    }

    private String name;
    private Double score;
    private String actor;
}

重写compareTo方法

posted @ 2024-05-30 21:43  折翼的小鸟先生  阅读(30)  评论(0)    收藏  举报