菜鸟之路Day09一一集合进阶(二)

devtools/2025/2/5 17:21:07/

菜鸟之路Day09一一集合进阶(二)

作者:blue

时间:2025.1.27

文章目录

  • 菜鸟之路Day09一一集合进阶(二)
    • 0.概述
    • 1.泛型
      • 1.1泛型概述
      • 1.2泛型类
      • 1.3泛型方法
      • 1.4泛型接口
      • 1.5泛型通配符
    • 2.Set系列集合
      • 2.1遍历方式
      • 2.2HashSet
      • 2.3LinkedHashSet
      • 2.4TreeSet

0.概述

内容学习至黑马程序员BV17F411T7Ao,无论如何,今天是值得铭记的一天,我们终于完结了200集的上部。下部漫漫,我们再接再厉。

1.泛型

1.1泛型概述

泛型:是JDK5中引入的新特性,可以在编译阶段约束操作的数据类型,并进行检查

泛型的格式:<数据类型>

注意:泛型只能支持引用数据类型(原因:数据在装入集合的过程中,会做一个泛型的擦除,也就是说在集合中实际存储的是Object类型的数据,而引用数据类型是继承Object的,这里利用了多态,所以这里必须使用引用数据类型。指定了泛型的具体类型后,传入数据时,可以传入该类类型或其子类类型)

泛型的好处:1.统一了数据类型;2.把运行时期的问题提前到了编译期间,避免了强制类型转换可能出现的异常,因为在编译阶段类型就能够确定下来

如果不写泛型,类型默认是Object

1.2泛型类

使用场景:当一个类中,某个变量的数据类型不确定时,就可以定义带有泛型的类

比如下面我们手写一个MyArrayList

java">import java.util.Arrays;public class MyArrayList<E> {Object[] obj = new Object[10];int size;public boolean add(E e){obj[size] = e;size++;return true;}public E get(int index) {return (E)obj[index];}@Overridepublic String toString() {return Arrays.toString(obj);}
}

使用一下我们自己写的MyArrayList

java">public class GenericsDemo1 {public static void main(String[] args) {MyArrayList<Integer> list = new MyArrayList<>();list.add(123);list.add(234);list.add(345);list.add(456);System.out.println(list.get(3));}
}

1.3泛型方法

方法中形参类型不确定时:方案①:使用类名后面定义的泛型(所有方法都能用);方案②:在方法申明上定义自己的泛型(只有本方法能用)

泛型方法的格式:

java">/*
修饰符 <类型> 返回值类型 方法名(类型 变量名){方法体
}
*/

练习:定义一个工具类:ListUtil

​ 类中定义一个静态方法addAll,用来添加多个集合的元素

java">package Generics;import java.util.ArrayList;public class ListUtil {private ListUtil(){}//工具类,私有化其构造方法//静态方法的话,泛型写在static之后public static<E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4){list.add(e1);list.add(e2);list.add(e3);list.add(e4);}
}

1.4泛型接口

java">/*修饰符 interface 接口名<类型>{}*/

泛型接口的重点在于:如何使用一个带泛型的接口

方式1:实现类给出具体的类型

java">public class MyArrayList implements List<String>

方式2:实现类延续泛型,创建对象时再确定

java">public class MyArrayList<E> implement List<E>
MyArrayList<String> list = new MyArrayList<>();

1.5泛型通配符

java">/*?也表示不确定类型他可以进行类型的限定? extends E:表示可以传递E或者E所有的子类类型? super E:表示可以传递E或者E所有父亲类型应用场景:1.如果我们在定义类,方法,接口的时候,如果类型不确定,就可以定义泛型类,泛型方法,泛型接口2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以使用泛型的通配符泛型的通配符:关键点:可以限定类型的范围
*/
java">package Generics;import java.util.ArrayList;public class GenericsDemo2 {public static void main(String[] args) {ArrayList<Ye> list1 = new ArrayList<>();ArrayList<Fu> list2 = new ArrayList<>();ArrayList<Zi> list3 = new ArrayList<>();method(list1);method(list2);method(list3);//method(new ArrayList<Integer>());这个就不行}public static void method(ArrayList<? extends Ye> list){}
}
class Ye {}
class Fu extends Ye{}
class Zi extends Fu {}

2.Set系列集合

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

Set集合的实现类特点

名字特点
HashSet无序,不重复,无索引
LinkedHashSet有序,不重复,无索引
TreeSet可排序,不重复,无索引

2.1遍历方式

Set还是属于Collection系列的所以它的API与Collection是一样,不同是其遍历方式,因为它是无索引的,所以只能用Collection通用的遍历方式,迭代器,增强for,Lambada表达式

java">package SetDemo;import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.function.Consumer;public class SetDemo1 {public static void main(String[] args) {HashSet<String> set = new HashSet<>();set.add("aaa");set.add("aaa");//利用set去重set.add("bbb");set.add("ccc");set.add("ddd");//迭代器遍历Iterator<String> it = set.iterator();while(it.hasNext()){System.out.println(it.next());}//增强forfor(String i:set){System.out.println(i);}//Lambda表达式set.forEach((String s)->{System.out.println(s);});}
}

2.2HashSet

HashSet集合的底层原理采取哈希表存取数据

哈希表是一种对于增删改查数据性能都较好的结构

哈希值

根据hashCode方法算出来的int类型的整数整数

该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算

一般情况下,会重写hashCode方法,利用对象内部属性值计算哈希值

注意:

​ 如果没有重写hashCode方法,不同对象计算出的哈希值是不同的

​ 如果重写hashCode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的

​ 在小部分情况下,不同属性值或者不同地址值计算出来的哈希值也有可能一样。(哈希碰撞)

练习:

需求

java">package SetDemo;import java.util.HashSet;public class HashSetDemo1 {public static void main(String[] args) {HashSet<Student> set = new HashSet<>();Student stu1 = new Student("zhangsan",11);Student stu2 = new Student("lisi",12);Student stu3 = new Student("wangwu",13);set.add(stu1);set.add(stu2);set.add(stu3);//这个添加是失败的,因为他是根据hashCode来去重的,我们重写了hashCode方法,使得属性一样的hashCode是一致的Student stu4 = new Student("zhangsan",11);System.out.println(set.add(stu4));//falseSystem.out.println(stu1.hashCode());System.out.println(stu4.hashCode());for(Student i : set){System.out.println(i);}}
}

2.3LinkedHashSet

有序,不重复,无索引

这里的有序指的是保证存储和取出的元素顺序是一致的,因为有序的要求更复杂,所以它的效率比HashSet的效率低一点

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

打印出来的顺序是,按照我们添加的顺序

java">public class LinkedHashSetDemo1 {public static void main(String[] args) {LinkedHashSet<Student> set = new LinkedHashSet<>();Student stu1 = new Student("zhangsan",11);Student stu2 = new Student("lisi",12);Student stu3 = new Student("wangwu",13);set.add(stu1);set.add(stu2);set.add(stu3);System.out.println(set);}
}

2.4TreeSet

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

可排序:按照元素的默认规则(有小到大)排序

TreeSet集合的底层是基于红黑树的数据结构实现排序的,增删改查的性能都比较好

java">//基本使用
package SetDemo;import java.util.Iterator;
import java.util.TreeSet;
import java.util.function.Consumer;public class TreeSetDemo1 {public static void main(String[] args) {TreeSet<Integer> ts = new TreeSet<>();ts.add(2);ts.add(1);ts.add(5);ts.add(4);ts.add(3);System.out.println(ts);//自动排序//增强forfor(Integer i : ts){System.out.print(i+" ");}System.out.println();//迭代器Iterator<Integer> it = ts.iterator();while(it.hasNext()){System.out.print(it.next()+" ");}System.out.println();//Lambadats.forEach((Integer i)->{System.out.print(i+" ");});}
}

TreeSet集合默认的规则

对于数值类型:Integer,Double,默认按照从小到大的顺序排序

对于字符,字符串类型:按照字符在ASCII码表中的数字升序进行排序

自定义类型如何排序

方式一:自然排序/默认排序:javabean类实现Comparable接口指定比较规则

java">package SetDemo;import java.util.Objects;public class Student implements Comparable<Student>{private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Student o) {//按照年龄大小排序return this.getAge()-o.getAge();}
}
java">package SetDemo;import java.util.TreeSet;public class TreeSetDemo2 {public static void main(String[] args) {Student stu1 = new Student("zhangsan",11);Student stu2 = new Student("lisi",12);Student stu3 = new Student("wangwu",13);TreeSet<Student> ts = new TreeSet<>();ts.add(stu1);ts.add(stu2);ts.add(stu3);System.out.println(ts);}
}

方式二:比较器排序,创建TreeSet对象的时候,传递比较器Comparator指定规则

java">package SetDemo;import java.util.Comparator;
import java.util.TreeSet;public class TreeSetDemo3 {public static void main(String[] args) {//按照长度排序,如果一样长则按照首字母排序TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {@Override/*o1:表示当前要添加的元素o2:表示已经在红黑树中的元素返回值的规则和之前是一样的*/public int compare(String o1, String o2) {//按照长度排序int i = o1.length()-o2.length();//如果一样长则按照首字母排序i=i==0?o1.compareTo(o2):i;//String的内置比较方法return i;}});ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");}
}

改为Lambada

java">package SetDemo;import java.util.Comparator;
import java.util.TreeSet;public class TreeSetDemo3 {public static void main(String[] args) {//按照长度排序,如果一样长则按照首字母排序TreeSet<String> ts = new TreeSet<>((String o1, String o2) ->{//按照长度排序int i = o1.length()-o2.length();//如果一样长则按照首字母排序i=i==0?o1.compareTo(o2):i;//String的内置比较方法return i;});ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");for (String i:ts){System.out.println(i);}}
}

http://www.ppmy.cn/devtools/156329.html

相关文章

什么是门控循环单元?

一、概念 门控循环单元&#xff08;Gated Recurrent Unit&#xff0c;GRU&#xff09;是一种改进的循环神经网络&#xff08;RNN&#xff09;&#xff0c;由Cho等人在2014年提出。GRU是LSTM的简化版本&#xff0c;通过减少门的数量和简化结构&#xff0c;保留了LSTM的长时间依赖…

开源 CSS 框架 Tailwind CSS v4.0

开源 CSS 框架 Tailwind CSS v4.0 于 1 月 22 日正式发布&#xff0c;除了显著提升性能、简化配置体验外&#xff0c;还增强了功能特性&#xff0c;具体如下1&#xff1a; 性能提升 采用全新的高性能引擎 Oxide&#xff0c;带来了构建速度的巨大飞跃&#xff1a; 全量构建速度…

图神经网络驱动的节点分类:从理论到实践

图神经网络驱动的节点分类:从理论到实践 1. 引言 图神经网络(Graph Neural Networks,GNN)作为处理图结构数据的强大工具,近年来在学术界和工业界都取得了显著进展。其独特的消息传递机制能够有效捕捉图数据中的复杂关系,为节点分类、链接预测、图分类等任务提供了新的解…

「全网最细 + 实战源码案例」设计模式——模板方法模式

核心思想 模板方法模式&#xff08;Template Method Pattern&#xff09;是一种行为型设计模式&#xff0c;定义了一个算法的骨架&#xff08;模板&#xff09;&#xff0c;将某些步骤延迟到子类中实现&#xff08;在不修改结构的情况下&#xff09;&#xff0c;以避免代码重复…

新春贺岁,共赴AGI之旅

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 往期精彩文章推荐 季姮教授独家文字版干货 | 面向知识渊博的大语言模型 关于AI TIME AI TIME源起于2019年&#xff0c;旨在发扬科学思辨精神&#xff0c;邀请各界人士对人工智能理论、算法和场景应用的本质问题…

神经网络|(七)概率论基础知识-贝叶斯公式

【1】引言 前序我们已经了解了一些基础知识。 古典概型&#xff1a;有限个元素参与抽样&#xff0c;每个元素被抽样的概率相等。 条件概率&#xff1a;在某条件已经达成的前提下&#xff0c;新事件发生的概率。实际计算的时候&#xff0c;应注意区分&#xff0c;如果是计算综…

Linux 系统上安装 Docker 方法详解与比较

Docker 是现代 DevOps 和容器化应用开发的重要工具&#xff0c;它简化了应用的部署和管理流程。本文将详细介绍在 Linux 系统上安装 Docker 的多种方法&#xff0c;并对它们的适用场景、优缺点进行对比&#xff0c;确保读者能够根据自身需求选择最优方案。 1. 官方推荐的安装方…

【游戏设计原理】98 - 时间膨胀

从上文中&#xff0c;我们可以得到以下几个启示&#xff1a; 游戏设计的核心目标是让玩家感到“时间飞逝” 游戏的成功与否&#xff0c;往往取决于玩家的沉浸感。如果玩家能够完全投入游戏并感受到时间飞逝&#xff0c;说明游戏设计在玩法、挑战、叙事等方面达到了吸引人的平衡…