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

news2024/12/23 23:23:43

文章目录

  • 一、集合类体系结构
  • 二、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/500129.html

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

相关文章

Java8新特性—Optional类

前言 Java 8中引入了一个新的Optional类&#xff0c;它可以让开发人员更好地处理可能为空的值。Optional类提供了一种方式&#xff0c;可以更加优雅地处理null值&#xff0c;并在运行时避免NullPointerException异常的出现。本文将介绍Optional类的基本语法、使用场景和示例。…

Java 基础进阶篇(十)—— 泛型与可变参数

文章目录 一、泛型概述二、泛型的定义2.1 泛型类2.2 泛型方法2.3 泛型接口 三、泛型深入3.1 泛型通配符3.2 泛型上下限3.3 案例&#xff1a;定义一个 “所有车量进行比赛” 的方法 四、可变参数 一、泛型概述 泛型是 JDK5 中引入的特性&#xff0c;可以在编译阶段约束操作的数…

Linux应用开发:进程间通信 System V

目录 1、查看删除IPC对象 1.1 IPC对象 1.2 ipcs 命令查看系统中的 IPC 对象 1.3 ipcrm 命令删除系统中的 IPC 对象 2、共享内存 2.1 共享内存简介 2.2 共享内存相关API 2.2.1 shmget&#xff1a;创建共享内存 2.2.2 shmat&#xff1a;映射共享内存 2.2.3 shmdt&#…

A40i使用笔记:安装python3.7(素装)

一、前言 项目需求&#xff0c;要用到python3以上&#xff0c;就研究了一下如何安装python&#xff0c;这里也是分享出来安装方法&#xff0c;为各位技术研发人员减少不必要的时间损耗 本文没有安装python其他依赖库&#xff0c;因为我也是在摸索中&#xff0c;所以只限指导到…

「程序员的浪漫」使用 Html、Css、JavaScript 实现 DIY 生日祝福页面 快发给你的朋友吧

前言 从网上搜集整理修改的好用网页生日祝福版本 特点 将三剑客放进一个 Html 文件 点开即用封装好 修改几个参数就可以 DIYDIY 的地方有注释 预览 …省略几张图 源码 有用的话点个 star 不迷路谢谢&#xff01;https://github.com/yangzi0210/Happy-birthday-page

领先的项目协作管理软件OpenProject

本文软件由网友 不长到一百四誓不改名 推荐&#xff1b; 什么是 OpenProject &#xff1f; OpenProject 是一个开源、基于 Web 的项目管理系统&#xff0c;提供了免费的社区版和收费的企业版。OpenProject 拥有完善的文档&#xff0c;API&#xff0c;及丰富的功能&#xff0c;可…

SlickEdit for Windows and Linux crack

SlickEdit for Windows and Linux crack 现在可以在“新建注释”对话框中对颜色进行排序&#xff0c;使调色板中的颜色阵列看起来更符合逻辑。 在拆分或扩展行注释时添加了撤消步骤&#xff0c;这样您只需点击“撤消”一次即可撤消行注释扩展。 已更新VHDL颜色编码&#xff0c;…

【网络】- 计算机网络体系结构 - OSI七层模型、TCP/IP四层(五层)协议

目录 一、概述 二、计算机网络体系结构的形成  &#x1f449;2.1 分层的网络体系结构  &#x1f449;2.2 OSI 参考模型  &#x1f449;2.3 TCP/IP - 事实的国际标准 三、OSI 参考模型 四、TCP/IP 协议 一、概述 但凡学习计算机网络知识&#xff0c;肯定绕不过网络协议的&…

Java 基础进阶篇(八)—— 常用 API

文章目录 一、Object 类二、Objects 工具类三、Math 类四、System 类五、BigDecimal 类 一、Object 类 一个类要么默认继承了 Object 类&#xff0c;要么间接继承了 Object 类&#xff0c;Object 类是 java 中的祖宗类。Object 类的方法是一切子类都可以直接使用的。 因此&…

7.4 电子信息系统预处理中所用放大电路

在电子信息系统中&#xff0c;通过传感器或其它途径所采集的信号往往很小&#xff0c;不能直接进行运算、滤波等处理&#xff0c;必须进行放大。 一、仪表放大器 集成仪表放大器&#xff0c;也称为精密放大器&#xff0c;用于弱信号放大。 1、仪表放大器的特点 在测量系统中…

Binder“一次拷贝“你真懂吗?

前言 谈到到Binder相对于其他传统进程间通信方式的优点的时候&#xff0c;我们总会说Binder只需要做“一次拷贝”就行了&#xff0c;而其他传统方式需要“两次拷贝”。这确实是Binder的优点&#xff0c;但再进一步思考就会碰到两个问题&#xff1a; 这所谓的“一次拷贝”到底…

回溯算法简单介绍

目录 1.回溯算法简单介绍 2.回溯算法框架&#xff1a; 我们用一道题来详细讲解回溯算法的过程 3.全排列问题 1.回溯算法简单介绍 解决一个回溯问题&#xff0c;其实就是一个决策树的遍历过程&#xff0c;我们只需要思考三个问题&#xff1a; 1.路径&#xff1a;就是已经做出…

一起Talk Android吧(第五百四十二回:无进度值ProgressBar)

文章目录 概念介绍使用资源文件实现使用默认设置修改风格使用动画资源 使用代码实现经验总结 各位看官们大家好&#xff0c;上一回中咱们说的例子是"ProgressBar总结",本章回中介绍的例子是" 无进度值ProgressBar"。闲话休提&#xff0c;言归正转&#xf…

linux相关操作

1 系统调用 通过strace直接看程序运行过程中的系统调用情况 其中每一行为一个systemcall &#xff0c;调用write系统调用将内容最终输出。 无论什么编程语言都必须通过系统调用向内核发起请求。 sar查看进程分别在用户模式和内核模式下的运行时间占比情况&#xff0c; ALL显…

MySQL的where表达式中的各种运算符的用法和细节

MySQL的where表达式中的各种运算符的用法和细节 小故事mysql运算符分类where表达式中的运算符between and 和 and运算符的区别in运算符需要注意的点 小故事 今天在研究mysql的where表达式中的运算符的时候&#xff0c;遇到一个有意思的问题。 问题是&#xff1a;以id为主键&am…

玩机搞机----修改手机各项参数工具解析 过验证 变新机

任何的芯片原则上都可以修改当前机型的任何参数。包括但不限于高通 MTk 展讯..... 等其他芯片。众所周知&#xff0c;有的机型 有的版本可以直接修改&#xff0c;有的不行。至于具体原因可以参考我以往的帖子 安卓玩机搞机技巧综合资源-----修复基带 改串码 基带qcn 改相关参数…

三、c++学习(指针引用详解)

上一次直播好像过去很久了&#xff0c;中间有加班&#xff0c;有5 1假期等&#xff0c;现在5 1放假完了&#xff0c;所以继续卷。 C学习&#xff0c;b站直播视频 3.1 指针 这个指针&#xff0c;考虑了很久&#xff0c;一直不知道在哪个地方介绍&#xff0c;为啥纠结&#xf…

Solr(2):Solr的安装

1 安装前的概述 &#xff08;1&#xff09;solr是基于lucene而lucene是java写的&#xff0c;所以solr需要jdk----当前安装的solr-7.5需要jdk-1.8及以上版本&#xff0c;下载安装jdk并设置JAVA_HOME即可。 &#xff08;2&#xff09;下载solr&#xff0c;然后解压即可&#xf…

Map对象的用法(JS)

&#x1f4dd;个人主页&#xff1a;爱吃炫迈 &#x1f48c;系列专栏&#xff1a;数据结构与算法 &#x1f9d1;‍&#x1f4bb;座右铭&#xff1a;道阻且长&#xff0c;行则将至&#x1f497; 文章目录 MapkeyMap常用语法Map其他语法创建map的其他方式 Map Map是一个键值对形式…

FPGA设计之控制集优化详解

目录 一、前言 二、Control Set控制集 三、Control Set控制集优化 四、优劣 一、前言 在工程设计优化中&#xff0c;综合阶段优化中有一项常见的优化&#xff0c;控制集&#xff08;control set&#xff09;优化&#xff0c;在vivado的Synthesis中有对该配置项的解释&#x…