Java 基础进阶篇(十)—— Java集合详细总结

news2024/9/30 5:26:27

文章目录

  • 一、集合类体系结构
  • 二、Collection系列集合
    • 2.1 Collection 集合体系
    • 2.2 Collection 集合体系特点
    • 2.3 Collection 常用API
    • 2.4 Collection 集合的遍历方式
      • 2.4.1 方式一:迭代器
      • 2.4.2 方式二:foreach(增强for循环)
      • 2.4.3 方式三:Lambda表达式
  • 三、List系列集合
    • 3.1 集合特点
    • 3.2 集合特有方法
    • 3.3 ArrayList 集合
    • 3.4 LinkedList集合
    • 3.5 遍历方式
      • 3.5.1 fori循环
      • 3.5.2 迭代器
      • 3.5.3 foreach
      • 3.5.4 Lambda
  • 四、Set 系列集合
    • 4.1 集合特点
    • 4.2 常用API
    • 4.3 哈希表
    • 4.4 HashSet 集合
      • 4.4.1 存储原理解析
      • 4.4.2 去重原理解析
    • 4.5 LinkedHashSet 集合
    • 4.6 TreeSet集合
      • 4.6.1 自定义排序
      • 4.6.2 去重原理解析
  • 五、Map系列集合
    • 5.1 Map 集合体系
    • 5.2 Map 集合体系特点
    • 5.3 Map 常用API
    • 5.4 Map 集合的遍历方式
    • 5.5 HashMap
    • 5.6 LinkedHashMap
    • 5.7 TreeMap
    • 5.7.1 自定义排序
    • 5.8 去重原理
  • 六、不可变集合


一、集合类体系结构

集合分为单列集合与双列集合,其中:
Collection 单列集合,每个元素(数据)只包含一个值。
Map 双列集合,每个元素包含两个值(键值对)。

在这里插入图片描述


二、Collection系列集合

2.1 Collection 集合体系

在这里插入图片描述


2.2 Collection 集合体系特点

  • List系列集合:添加的元素是有序、可重复、有索引

    • ArrayList、LinekdList:有序、可重复、有索引。
  • Set系列集合:添加的元素是无序、不重复、无索引

    • HashSet:无序、不重复、无索引。
    • LinkedHashSet:有序、不重复、无索引。
    • TreeSet:按照大小默认升序排序、不重复、无索引。
  • 约定集合存储数据:集合和泛型不支持基本类型,只支持引用数据类型
    在这里插入图片描述
    注:集合中要存储基本数据类型可以使用包装类。


2.3 Collection 常用API

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

在这里插入图片描述
示例:

public static void main(String[] args) {
        // ArrayList:添加的元素是有序,可重复,有索引。
        Collection<String> c = new ArrayList<>();
        // 1.添加元素, 添加成功返回true。
        c.add("Java");
        c.add("HTML");
        c.add("HTML");
        c.add("MySQL");
        c.add("Java");
        System.out.println(c); // [Java, HTML, HTML, MySQL, Java]

        // 2.清空集合的元素。
        // c.clear();
        // System.out.println(c);

        // 3.判断集合是否为空 是空返回true,反之。
        // System.out.println(c.isEmpty());

        // 4.获取集合的大小。
        System.out.println(c.size());

        // 5.判断集合中是否包含某个元素。
        System.out.println(c.contains("Java"));  // true
        System.out.println(c.contains("java")); // false

        // 6.删除某个元素:如果有多个重复元素默认删除前面的第一个!
        System.out.println(c.remove("Java")); // true
        System.out.println(c); // [HTML, HTML, MySQL, Java]

        // 7.把集合转换成数组
        Object[] arrs = c.toArray();
        System.out.println("数组:" + Arrays.toString(arrs)); // 数组:[HTML, HTML, MySQL, Java]
        // 注:Arrays工具类的toString方法格式化输出的是数组内容
}
public static void main(String[] args) {
        // 拓展 boolean addAll(Collection<? extends E> c) 批量添加
        Collection<String> c1 = new ArrayList<>();
        c1.add("java1");
        c1.add("java2");
        Collection<String> c2 = new ArrayList<>();
        c2.add("赵敏");
        c2.add("殷素素");
        // addAll把c2集合的元素全部倒入到c1中去。
        c1.addAll(c2);
        System.out.println(c1); // [java1, java2, 赵敏, 殷素素]
        System.out.println(c2); // [赵敏, 殷素素]
}

2.4 Collection 集合的遍历方式

2.4.1 方式一:迭代器

迭代器在 Java 中的代表是 Iterator,迭代器是集合的专用的遍历方式。

获取迭代器:
在这里插入图片描述
Iterator中的常用方法:
在这里插入图片描述

示例:

在这里插入图片描述

注:lists是多态的定义方式(三种情况都可)

Collection<String> lists = new ArrayList<>();
List<String> lists = new ArrayList<>();
ArrayList<String> lists = new ArrayList<>();

2.4.2 方式二:foreach(增强for循环)

既可以遍历集合也可以遍历数组,基本格式如下:

在这里插入图片描述
举例:
在这里插入图片描述

注:

由于 List 系列集合有索引,因此也可用常规的 fori 循环遍历。
但由于多态,父类不可调用子类独有功能,因此不可调用子类的 fori 遍历形式,需要强制类型转换

Set 系列集合没有索引不可用 fori 循环。

修改第三方变量的值不会影响到集合中的对象,但是会影响对象里面的值。

示例1:

Collection<String> lists = new ArrayList<>();
lists.add("赵敏");
lists.add("小昭");
lists.add("殷素素");
for (String ele : lists) {
	if(ele.equals("赵敏")){
		ele = "新名字";
	}
}
System.out.println(lists); // [赵敏, 小昭, 殷素素]
Collection<Student> students = new ArrayList<>();
students.add(new Student("王明", 12));
students.add(new Student("乌戈", 36));
students.add(new Student("李霞", 24));
for (Student student : students) {
	if(student.getName().equals("乌戈")){
		student = new Student("新来的", 22);
	}
}
System.out.println(students);
 // [Student{name='王明', age=12}, Student{name='乌戈', age=36}, Student{name='李霞', age=24}]

示例2:

Collection<Student> students = new ArrayList<>();
students.add(new Student("王明", 12));
students.add(new Student("乌戈", 36));
students.add(new Student("李霞", 24));
for (Student student : students) {
	if(student.getName().equals("乌戈")){
		student.setName("呜呜");
	}
}
System.out.println(students); 
// [Student{name='王明', age=12}, Student{name='呜呜', age=36}, Student{name='李霞', age=24}]

2.4.3 方式三:Lambda表达式

得益于JDK 8开始的新技术 Lambda 表达式,提供了一种更简单、更直接的遍历集合的方式。

遍历的API:Consumer是一个函数式接口,可通过匿名内部类实现或者子类实现。

在这里插入图片描述

示例:

在这里插入图片描述
以上形式还可以简化:lists.forEach( System.out::println );

调用流程解析,可参考匿名内部类:
在这里插入图片描述   在这里插入图片描述


三、List系列集合

3.1 集合特点

ArrayList、LinekdList :有序,可重复,有索引。

  • 有序:存储和取出的元素顺序一致
  • 有索引:可以通过索引操作元素
  • 可重复:存储的元素可以重复

3.2 集合特有方法

在这里插入图片描述
注:Collection的功能 List 也都继承了。

示例:

public static void main(String[] args) {
	// 1.创建一个ArrayList集合对象:
	// List:有序,可重复,有索引的。
	List<String> list = new ArrayList<>(); // 一行经典代码!
	list.add("Java");
	list.add("Java");
	list.add("HTML");
	list.add("MySQL");
	list.add("MySQL");
	
	// 2.在某个索引位置插入元素。
	list.add(2, "黑马");
	System.out.println(list); // [Java, Java, 黑马, HTML, MySQL, MySQL]
	
	// 3.根据索引删除元素,返回被删除元素
	System.out.println(list.remove(1)); // Java
	System.out.println(list); // [Java, 黑马, HTML, MySQL, MySQL]
	
	// 4.根据索引获取元素
	System.out.println(list.get(1));
	
	// 5.修改索引位置处的元素
	System.out.println(list.set(1, "传智教育"));
	System.out.println(list); // [Java, 传智教育, HTML, MySQL, MySQL]
}

3.3 ArrayList 集合

ArrayList 底层是基于数组实现的,根据查询元素快,增删相对慢


3.4 LinkedList集合

LinkedList底层基于双链表实现的,查询元素慢,增删首尾元素非常快

在这里插入图片描述

public static void main(String[] args) {
	// LinkedList可以完成队列结构,和栈结构 (双链表)
	// 1、做一个队列:
	LinkedList<String> queue = new LinkedList<>();
	// 入队
	queue.addLast("1号");
	queue.addLast("2号");
	queue.addLast("3号");
	System.out.println(queue); // [1号, 2号, 3号]
	// 出队
	System.out.println(queue.getFirst()); // 1号
	System.out.println(queue.removeFirst()); // 1号
	System.out.println(queue.removeFirst()); // 2号
	System.out.println(queue); // [3号]
	
	// 2、做一个栈
	LinkedList<String> stack = new LinkedList<>();
	// 入栈 压栈 (push)
	stack.push("第1颗子弹"); // push 方法就是 addFirst
	stack.push("第2颗子弹");
	stack.push("第3颗子弹");
	stack.push("第4颗子弹");
	System.out.println(stack); // [第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]
	
	// 出栈  弹栈 pop
	System.out.println(stack.pop()); // pop 方法就是 removeFirst
	System.out.println(stack.pop());
	System.out.println(stack); // [第2颗子弹, 第1颗子弹]
}

3.5 遍历方式

两种形式都可。

List<String> lists = new ArrayList<>();
List<String> lists = new LinkedList<>();

3.5.1 fori循环

for (int i = 0; i < lists.size(); i++) {
	String ele = lists.get(i);
	System.out.println(ele);
}

3.5.2 迭代器

Iterator<String> it = lists.iterator();
while (it.hasNext()){
	String ele = it.next();
	System.out.println(ele);
}

3.5.3 foreach

for (String ele : lists) {
	System.out.println(ele);
}

3.5.4 Lambda

lists.forEach(s -> {
	System.out.println(s);
});
lists.forEach( System.out::println );

四、Set 系列集合

4.1 集合特点

Set系列集合:添加的元素是无序、不重复、无索引

  • HashSet:无序、不重复、无索引。
  • LinkedHashSet:有序、不重复、无索引。
  • TreeSet:按照大小默认升序排序、不重复、无索引。

没有带索引的方法,所以不能使用普通 fori 循环遍历,也不能通过索引来获取元素。


4.2 常用API

Set 集合的功能上基本上与 Collection 的 API 一致


4.3 哈希表

在这里插入图片描述


4.4 HashSet 集合

特点 : 无序、不重复、无索引
原理:HashSet 集合底层采取哈希表存储的数据

4.4.1 存储原理解析

JDK8之前的版本,哈希表底层使用数组+链表组成。
在这里插入图片描述

JDK8开始后,新元素挂老元素下面,哈希表底层采用数组+链表+红黑树组成。
在这里插入图片描述
JDK1.8及以上版本,当挂在元素下面的数据过多时,查询性能降低,从JDK8开始后,当链表长度超过8的时候,自动转换为红黑树。


4.4.2 去重原理解析

参考上方哈希表的创建流程:

① 创建一个默认长度 16,默认加载因为 0.75的数组,数组名 table。
② 根据元素的哈希值跟数组的长度计算出应存入的位置
③ 判断当前位置是否为null,如果是 null 直接存入,如果位置不为 null,表示有元素,
  则调用 equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组中该位置的链表。
④ 当数组存满到 16*0.75=12时,就自动扩容,每次扩容原先的两倍。

如果希望 Set 集合认为 2 个内容一样的对象是重复的,必须重写对象的 hashCode() 和 equals() 方法。

示例:构造、set、get 和 toString方法。

public class Student {
    private String name;
    private int age;
    private char sex;

    /**
     * 重写 equals 方法
     * 只要两个对象内容一样,结果一定是true
     */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && sex == student.sex && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, sex);
    }
}
public static void main(String[] args) {
	HashSet<Student> sets = new HashSet<>();
	Student s1 = new Student("舞阳", 20, '男');
	Student s2 = new Student("舞阳", 20, '男');
	Student s3 = new Student("周雄", 21, '女');
	Student s4 = new Student("王祖", 17, '男');
	
	// 重写 hasCode 方法后,返回的 哈希值相同
	System.out.println(s1.hashCode()); // 1029350039
	System.out.println(s2.hashCode()); // 1029350039
	
	// 添加集合时候,先判断 hashCode 值,定位哈希表的同一个位置。
	// 再通过重写的 equals 方法判断内容是否相等
	sets.add(s1);
	sets.add(s2);
	sets.add(s3);
	sets.add(s4);
	
	System.out.println(sets);
	// [Student{name='周雄', age=21, sex=女}, Student{name='舞阳', age=20, sex=男}, Student{name='王祖', age=17, sex=男}]
}

4.5 LinkedHashSet 集合

特点:有序、不重复、无索引。有序指的是保证存储和取出的元素顺序一致。
原理:底层数据结构是依然哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序
在这里插入图片描述

示例:

public static void main(String[] args) {
	// 有序 不重复 无索引
	Set<String> sets2 = new LinkedHashSet<>();
	sets2.add("MySql");
	sets2.add("MySql");
	sets2.add("Java");
	sets2.add("Java");
	sets2.add("MyBatis");
	sets2.add("Html");
	sets2.add("Html");
	System.out.println(sets2); // [MySql, Java, MyBatis, Html]
}

4.6 TreeSet集合

特点:排序、不重复、无索引。可排序:按照元素的大小默认升序排序。
原理:底层是基于纯红黑树的数据结构实现排序的,增删改查性能都较好


4.6.1 自定义排序

TreeSet 集合是一定要排序的,可以将元素按照指定的规则进行排序

默认规则:

① 对于数值类型:Integer、Double,官方默认按照大小进行升序排序。
② 对于字符串类型:默认按照首字符的编号升序排序。
③ 对于自定义类型如Student对象,TreeSet无法直接排序。

自定义排序规则:
方式一: 实现 Comparable 接口重写里面的 compareTo方法来定制比较规则
方式二:TreeSet 集合有参数构造器,可以设置 Comparator 接口对应的比较器对象,来定制比较规则

例1:实现 Comparable 接口,重写比较规则。

public class Apple implements Comparable<Apple>{
    private String name;
    private String color;
    private double price;
    private int weight;

    /**
      方式一:实现 Comparable 接口,类自定义比较规则
      o1.compareTo(o2)
     */
    @Override
    public int compareTo(Apple o) {
        // 按照重量进行比较的
        return this.weight - o.weight ; // 去除 重量 重复的元素
        // return this.weight - o.weight >= 0 ? 1 : -1; // 保留 重量 重复的元素
    }
}
public static void main(String[] args) {
	// 方式一:类自定义比较规则
	TreeSet<Apple> apples = new TreeSet<>();
	apples.add(new Apple("红富士", "红色", 9.9, 500));
	apples.add(new Apple("青苹果", "绿色", 15.9, 300));
	apples.add(new Apple("绿苹果", "青色", 29.9, 400));
	apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
	System.out.println(apples); 
	// [Apple{name='青苹果', ..., weight=300}, Apple{name='绿苹果', ..., weight=400}, Apple{name='红富士', ..., weight=500}]
}

例2:调用比较器对象的有参构造,进行规则定制。

public static void main(String[] args) {
	// 方式二:集合自带比较器对象进行规则定制
	TreeSet<Apple> apples2 = new TreeSet<>(new Comparator<Apple>() {
		@Override
		public int compare(Apple o1, Apple o2) {
			return o1.getWeight() - o2.getWeight(); // 升序
			// return o2.getWeight() - o1.getWeight(); // 降序
			// return Double.compare(o1.getPrice(), o2.getPrice()); // 价格升序
		}
	});
	// Lambda 化简形式
	// TreeSet<Apple> apples3 = new TreeSet<>((o1, o2) -> Double.compare(o1.getPrice(), o2.getPrice()));
	
	apples2.add(new Apple("红富士", "红色", 9.9, 500));
	apples2.add(new Apple("青苹果", "绿色", 15.9, 300));
	apples2.add(new Apple("绿苹果", "青色", 29.9, 400));
	apples2.add(new Apple("黄苹果", "黄色", 9.8, 500));
	System.out.println(apples2);
	// [Apple{name='青苹果', ..., weight=300}, Apple{name='绿苹果', ..., weight=400}, Apple{name='红富士', ..., weight=500}]
}

当两种方式同时出现时采用就近原则,使用匿名内部类的方式,即第二种方式

注:根据浮点类型变量比较时,一定要使用包装类的 API。
如按照价格升序,价格是 double 类型,return Double.compare(o1.getPrice(), o2.getPrice()); ,原因在于两个浮点数相减,再强转成 int 类型( compare 方法返回 int 类型),有可能使得值为 0,如:(int)(5.8-5.8)。

另外,如果价格相同,保留重复的元素,可以采用如下方式:

TreeSet<Apple> apples2 = new TreeSet<>(new Comparator<Apple>() {
	@Override
	public int compare(Apple o1, Apple o2) {
		int compare = Double.compare(o1.getPrice(), o2.getPrice());
		return compare>=0 ? 1 : -1; // 价格升序
	}
});

例3:倒序排序

TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() {
	@Override
	public int compare(Integer o1, Integer o2) {
		return o2 - o1;
	}
});
set.add(2);
set.add(1);
set.add(34);
System.out.println(set); // [34, 2, 1]

4.6.2 去重原理解析

TreeSet 在自定义排序中,重写 equals 方法和 hasCode 方法不会起作用,TreeSet 只走 compareTo 方法。但是可通过设置多重条件来判断属性相同的集合的去重情况。

public class Apple implements Comparable<Apple>{
    private String name;
    private String color;
    private double price;
    private int weight;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Apple apple = (Apple) o;
        return Double.compare(apple.price, price) == 0 && weight == apple.weight && Objects.equals(name, apple.name) && Objects.equals(color, apple.color);
    }

    /**
      类自定义比较规则
      o1.compareTo(o2)
     * @param o
     * @return
     */
    @Override
    public int compareTo(Apple o) {
        boolean flag = this.equals(o);
        if(flag){ // 两个对象成员都相同
            return 0; // 去重
        }
        // 按照重量进行比较的
        return this.weight - o.weight ; // 去除 重量 重复的元素
        // return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
    }
}
public class SetDemo {
    public static void main(String[] args) {
        // 类自定义比较规则
        TreeSet<Apple> apples = new TreeSet<>();
        apples.add(new Apple("红富士", "红色", 9.9, 500));
        apples.add(new Apple("红富士", "红色", 9.9, 500));
        apples.add(new Apple("青苹果", "绿色", 15.9, 300));
        apples.add(new Apple("绿苹果", "青色", 29.9, 400));
        apples.add(new Apple("黄苹果", "黄色", 9.8, 500));
        System.out.println(apples);
        // [Apple{name='青苹果', ..., weight=300}, Apple{name='绿苹果', ..., weight=400}, Apple{name='红富士', ..., weight=500}]
    }
}

五、Map系列集合

5.1 Map 集合体系

在这里插入图片描述
使用最多的Map集合是HashMap,重点掌握HashMap、LinkedHashMap、TreeMap。


5.2 Map 集合体系特点

Map集合是一种双列集合,每个元素包含两个数据,也被称为 “键值对集合”。
Map集合的每个元素的格式:key=value(键值对元素)

Map 集合的完整格式:{key1=value1 , key2=value2 , key3=value3 , ...}
对比 Collection 集合的格式:[元素1,元素2,元素3..]

Map 集合下的实现类的特点都是由键决定

  • HashMap:无序、不重复、无索引
  • LinkedHashMap:有序、不重复、无索引。
  • TreeMap:不重复、无索引、可排序

5.3 Map 常用API

Map 是双列集合的祖宗接口,它的功能是全部双列集合都可以继承使用的。
在这里插入图片描述

public static void main(String[] args) {
	// 1.添加元素: 无序,不重复,无索引。
	Map<String , Integer> maps = new HashMap<>(); // 一行经典代码
	maps.put("iphoneX",10);
	maps.put("娃娃",20);
	maps.put("iphoneX",100);//  Map集合后面重复的键对应的元素会覆盖前面重复的整个元素!
	maps.put("huawei",100);
	maps.put("生活用品",10);
	maps.put("手表",10);
	// {huawei=100, 手表=10, 生活用品=10, iphoneX=100, 娃娃=20}
	System.out.println(maps);

	// 2.清空集合
	// maps.clear();
	// System.out.println(maps);
	
	// 3.判断集合是否为空,为空返回true,反之为 false
	System.out.println(maps.isEmpty());
	
	// 4.根据键获取对应值:public V get(Object key)
	Integer value = maps.get("huawei");
	System.out.println(value);// 100
	System.out.println(maps.get("生活用品2")); // null
	
	// 5.根据键删除整个元素。(删除键会返回键的值)
	System.out.println(maps.remove("iphoneX"));
	System.out.println(maps);
	
	// 6.判断是否包含某个键 ,包含返回true,反之为 false
	System.out.println(maps.containsKey("娃娃"));  // true
	System.out.println(maps.containsKey("娃娃2"));  // false
	System.out.println(maps.containsKey("iphoneX")); // false
	
	// 7.判断是否包含某个值。
	System.out.println(maps.containsValue(100)); //true
	System.out.println(maps.containsValue(10)); //true
	System.out.println(maps.containsValue(22)); //false
	
	// {huawei=100, 手表=10, 生活用品=10, 娃娃=20}
	// 8.获取全部键的集合:public Set<K> keySet()
	Set<String> keys = maps.keySet();
	System.out.println(keys); // [huawei, 手表, 生活用品, 娃娃]

	// 9.获取全部值的集合:Collection<V> values();
	Collection<Integer> values = maps.values();
	System.out.println(values); // [100, 10, 10, 20]
	
	// 10.集合的大小
	System.out.println(maps.size()); // 4
	
	// 11.合并其他Map集合。(拓展)
	Map<String , Integer> map1 = new HashMap<>();
	map1.put("java1", 1);
	map1.put("java2", 100);
	Map<String , Integer> map2 = new HashMap<>();
	map2.put("java2", 1);
	map2.put("java3", 100);
	map1.putAll(map2); // 把集合map2的元素拷贝一份到map1中去
	System.out.println(map1); // {java3=100, java2=1, java1=1}
	System.out.println(map2); // {java3=100, java2=1}
}

5.4 Map 集合的遍历方式

方式一:先获取Map集合全部的键,再根据遍历键找值
在这里插入图片描述

// 1、键找值:第一步:先拿到集合的全部键。
Set<String> keySet = maps.keySet();
// 2、第二步:遍历每个键,根据键提取值
for (String key : keySet) {
      Integer value = maps.get(key);
      System.out.println(key + "==>" + value);
}

方式二:键值对的方式遍历,把“键值对“看成一个整体,难度较大
在这里插入图片描述

// 1、把Map集合转换成Set集合
// 将键和值封装成实体类对象,再将该对象加入到set集合
Set<Map.Entry<String, Integer>> entries = maps.entrySet();
// 2、开始遍历
for (Map.Entry<String, Integer> entry : entries) {
      String key = entry.getKey();
      Integer value = entry.getValue();
      // System.out.println(maps.get(key));
      System.out.println(key + "==>" + value);
}

方式三:JDK1.8 开始之后的新技术:Lambda表达式
在这里插入图片描述

maps.forEach(new BiConsumer<String, Integer>() {
	@Override
	public void accept(String key, Integer value) {
	   System.out.println(key + "--->" + value);
	}
});
// Lambda 化简
maps.forEach((k, v) -> {
	System.out.println(k + "--->" + v);
});
maps.forEach((k, v) -> System.out.println(k + "--->" + v));

注:底层原理参考 Collection 集合 Lamdba 遍历方式。


5.5 HashMap

特点都是由键决定的:无序、不重复、无索引

没有额外需要学习的特有方法,直接使用 Map 里面的方法就可以了。

底层实现:Set 系列集合的底层就是 Map 实现的,只是 Set 集合中的元素只要键数据,不要值数据而已
在这里插入图片描述

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

在这里插入图片描述


5.6 LinkedHashMap

特点都是由键决定:有序、不重复、无索引。有序指的是保证存储和取出的元素顺序一致

底层实现:底层数据结构是依然哈希表,只是每个键值对元素又额外的多了一个双链表的机制记录存储的顺序。


5.7 TreeMap

特点由键决定特性:不重复、无索引、可排序
可排序:按照键数据的大小默认升序(由小到大)排序,且只能对键排序。

底层实现:TreeMap跟TreeSet一样的,基于红黑树。

5.7.1 自定义排序

方式一:类实现 Comparable 接口,重写比较规则

public class Apple implements Comparable<Apple>{
    private String name;
    private String color;
    private double price;
    private int weight;

    /**
      方式一:类自定义比较规则
      o1.compareTo(o2)
     */
    @Override
    public int compareTo(Apple o) {
        // 按照重量进行比较的
        return this.weight - o.weight ; // 去除 重量 重复的元素
        // return this.weight - o.weight >= 0 ? 1 : -1; // 保留重量重复的元素
    }
}
public static void main(String[] args) {
	Map<Apple, String> maps2 = new TreeMap<>();
	maps2.put(new Apple("红富士", "红色", 9.9, 500), "山东");
	maps2.put(new Apple("青苹果", "绿色", 15.9, 300), "广州");
	maps2.put(new Apple("绿苹果", "青色", 29.9, 400), "烟台");
	maps2.put(new Apple("黄苹果", "黄色", 9.8, 500), "江西");
	System.out.println(maps2);
	// {Apple{name='青苹果', ..., weight=300}=广州, 
	// Apple{name='绿苹果', ..., weight=400}=烟台, 
	// Apple{name='红富士', ..., weight=500}=江西}
}

方式二:集合自定义 Comparator 比较器对象,调用有参构造,重写比较规则

public static void main(String[] args) {
	Map<Apple, String> appleMap = new TreeMap<>(new Comparator<Apple>() {
		@Override
		public int compare(Apple o1, Apple o2) {
			return o1.getWeight() - o2.getWeight();
		}
	});
	
	// Map<Apple, String> appleMap2 = new TreeMap<>(( o1,  o2) -> o1.getWeight() - o2.getWeight()); // Lambda化简
	System.out.println(appleMap);
}

5.8 去重原理

HashMap、LinkedHashMap 去重原理与 Set 集合是相通的,可以通过重写 hasCode 方法和 equals 方法实现,内容相同的对象不可重复添加的效果。

将键和值作为一个整体(Entry对象)的哈希值求余放入数组中,然后通过equals方法对比。

TreeMap底层原理和TreeSet相同,纯红黑树。


六、不可变集合

不可变集合,就是不可被修改的集合。

集合的数据项在创建的时候提供,并且在整个生命周期中都不可改变,否则报错。

在这里插入图片描述

注:JDK 9 以后的版本才有不可变集合。

public static void main(String[] args) {
	// 1、不可变的List集合
	List<Double> lists = List.of(569.5, 700.5, 523.0,  570.5);
	// lists.add(689.0); // 报错
	// lists.set(2, 698.5); // 报错
	double score = lists.get(1);
	System.out.println(score);
	
	// 2、不可变的Set集合
	Set<String> names = Set.of("迪丽热巴", "迪丽热九", "马尔扎哈", "卡尔眨巴" );
	// names.add("三少爷"); // 报错
	System.out.println(names);
	
	// 3、不可变的Map集合
	Map<String, Integer> maps = Map.of("huawei", 2, "Java开发", 1, "手表", 1);
	// maps.put("衣服", 3); // 报错
	System.out.println(maps);
}

文章参考:Java入门基础视频教程,java零基础自学就选黑马程序员Java入门教程(含Java项目和Java真题)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/485707.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python系列之Windows环境安装配置

目录 一、Python安装 1.1下载 1.2 安装 1.3增加环境变量 二、PyCharm安装 2.1 PyCharm简介 2.2 PyCharm下载安装 一、Python安装 1.1下载 python 官网The official home of the Python Programming Languagehttps://www.python.org/downloads/ 1.2 安装 要勾选选项 Ad…

校园兼职平台系统的设计与实现

技术栈&#xff1a; Spring、SpringMVC、MyBatis、HikariCP、fastjson、slf4j、EL和JSTL 系统功能&#xff1a; 前台&#xff1a; &#xff08;1&#xff09;用户注册&#xff1a;这里的用户分为职位发布者和职位应聘者&#xff0c;他们都需要注册本大学生兼职管理系统才能进…

为什么 OpenAI 团队采用 Python 开发他们的后端服务?

Python&#xff0c;年龄可能比很多读者都要大&#xff0c;但是它在更新快速的编程界却一直表现出色&#xff0c;甚至有人把它比作是编程界的《葵花宝典》&#xff0c;只是Python的速成之法相较《葵花宝典》有过之而无不及。 Python简洁&#xff0c;高效的特点&#xff0c;大大…

196页11万字智慧水务平台建设方案

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除。 业务需求分析 3.1 主要业务描述 &#xff08;1&#xff09;调度中心主要业务描述 配套工程调度中心为一级调度机构&#xff0c;同时也是水务集团原水供水的统一调度中心。…

python-pandas库

目录 目录 目录 1.pandas库简介&#xff08;https://www.gairuo.com/p/pandas-overview&#xff09; 2.pandas库read_csv方法&#xff08;https://zhuanlan.zhihu.com/p/340441922?utm_mediumsocial&utm_oi27819925045248&#xff09; 1.pandas库简介&#xff08;http…

第七章 使用ssh服务管理远程主机

第七章 使用ssh服务管理远程主机 一、配置网卡服务 1、配置网卡参数 &#xff08;1&#xff09;、执行nmtui命令运行网络配置工具 [rootcentos ~]# nmtui&#xff08;2&#xff09;、选择编辑连接并按回车 &#xff08;3&#xff09;、选择以太网中网卡名称并编辑 &#xf…

JavaWeb06(三层架构连接数据库)

目录 三层架构 1.什么是三层架构 三层架构 就是将整个业务划分为三层&#xff1a;表示层、业务逻辑层、数据访问层。 2. 层与层之间的关系 3.怎么理解三层架构 4.为什么需要三层架构 区分层次的目的是为了“高内聚&#xff0c;低耦合”的思想&#xff1b; 简单来说&…

从零开始学习Linux运维,成为IT领域翘楚(五)

文章目录 &#x1f525;Linux打包压缩与搜索命令&#x1f525;Linux常用系统工作命令&#x1f525;Linux管道符、重定向与环境变量&#x1f525;管道命令符 &#x1f525;Linux打包压缩与搜索命令 tar 命令 语法&#xff1a; tar [选项] [文件]选项: &#x1f41f; -c 产生.t…

牛客网---CM11 链表分割 代码详解+哨兵位的比较

文章目录 前言CM11 链表分割链接&#xff1a;方法一&#xff1a;尾插(带哨兵位)1.1 思路&#xff1a;1.2 代码&#xff1a;1.3 流程图1.4 注意点 方法二&#xff1a;尾插(不带哨兵位)2.1代码&#xff1a; 对比&#xff1a; 总结 前言 独处未必孤独喜欢就是自由 本章的内容是牛…

Chapter4:频率响应法(上)

第四章:频率响应法 Exercise4.1 已知微分网络和积分网络电路图如下图所示,求网络的频率特性。 解: 【图 ( a ) ({\rm a}) (a)微分网络】 由微分网络电路图可得:

c# 运算符重载

1.概要 1.1可重载运算符 可重载运算符说明 x, -x, !x, ~x, , --, true, falsetrue和 false 运算符必须一起重载。 x y, x - y, x * y, x / y, x % y, x & y, x | y, x ^ y, x << y, x >> y, x >>> y x y, x ! y, x < y, x > y, x < y,…

使用NNI对BERT模型进行粗剪枝、蒸馏与微调

前言 模型剪枝&#xff08;Model Pruning&#xff09;是一种用于减少神经网络模型尺寸和计算复杂度的技术。通过剪枝&#xff0c;可以去除模型中冗余的参数和连接&#xff0c;从而减小模型的存储需求和推理时间&#xff0c;同时保持模型的性能。模型剪枝的一般步骤&#xff1a…

OpenAI文本生成器-怎么解决openai只写一半

openai写文案写一半没了怎么解决 如果您正在使用 OpenAI 写文案的服务&#xff0c;在撰写文案的过程中遇到了意外中断或者其他问题导致文案未保存&#xff0c;以下是一些有用的解决方法&#xff1a; 重新调用 API 去生成文案。您可以调用 OpenAI 的 API 重新获取您所需的文案…

Three.js--》几何体顶点知识讲解

目录 几何体顶点位置数据 点线定义几何体顶点数据 网格模型定义几何体顶点数据 顶点法线数据 实现阵列立方体与相机适配 常见几何体简介 几何体的旋转、缩放、平移方法 几何体顶点位置数据 本篇文章主要讲解几何体的顶点概念&#xff0c;相对偏底层一些&#xff0c;不过…

魔兽世界商业服务端定制商人自定义NPC教程

魔兽世界自定义NPC教程 大家好&#xff0c;我是艾西今天跟大家聊一下自定义NPC&#xff0c;自定义NPC可以添加自己想要售卖的物品以及定价等可以更好的将一个游戏设定以及游戏的拓展性有质的提升 creature表是游戏所有生物人物等表格 Creature_template是所有生物模板&#xf…

kafka快的原因(四)

四、kafka快的原因 4.1 顺序读写page cache 见上一节文件系统 使用6个7200rpm、SATA接口、RAID-5的磁盘阵列在JBOD配置下的顺序写入的性能约为600MB/秒&#xff0c;但随机写入的性能仅约为100k/秒&#xff0c;相差6000倍以上。 4.2 网络模型 4.2.1 reactor模型 4.2.2 epo…

kubernetes项目部署

目录 ​一、容器交付流程 二、k8s平台部署项目流程 三、在K8s平台部署项目 一、容器交付流程 容器交付流程通常分为四个阶&#xff1a;开发阶段、持续集成阶段、应用部署阶段和运维阶段。 开发阶段&#xff1a;开发应用程序&#xff0c;编写Dockerfile; 持续集成阶段&#…

gradle 模块

目录 ​settings.gradle文件的作用 SourceSet类的作用 Plugin 插件 Java 对 Plugin 的扩展 settings.gradle文件的作用 settings用于配置哪些工程是要被gradle集成的&#xff0c;gradle 通过 Settings.java 类来处理 settings.gradle 文件。 gradle的初始化阶段&#xff0c…

【音视频处理】RTMP、HLS、HTTP-FLV、WebRTC、RTSP的区别?直播协议详解

大家好&#xff0c;欢迎来到停止重构的频道。 本期我们详细讨论直播的相关协议&#xff0c;包括&#xff1a;HTTP-FLV、HLS、RTMP、Web-RTC、RTSP等等。 我们将会详细介绍这些协议的工作原理、应用场景、及延迟的原因。 我们按这样的顺序讨论​ 1、 RTMP、HTTP-FLV 2、 …

【五一创作】红黑树数据结构

现在JAVASE中HashMap中底层源码是由数组链表红黑树进行设计的&#xff0c;然后很多地方也是用到红黑树&#xff0c;这里单独对红黑树数据结构进行简单的介绍。 目录 红黑树概念 红黑树的性质 自平衡规则 代码 红黑树概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;…