泛型
提供了编译时类型安全检测机制
好处:
1.把运行时期的问题提前到了编译期间
2.避免了强制类型转换
day10-02 Set
Set
特点:
1.可以去除重复
2.存取顺序不一致
3.没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取,删除Set集合里面的元素
TreeSet
1.不包含重复元素的集合
2.没有带索引的方法
3.可以将元素按照规则进行排序
如果要使用TreeSet,必须指定排序规则。比如是个TreeSet<Integer>那么会默认按数字排序,如果是个Student这种对象就会报错。重写排序规则有两种方法:
1.自然排序Comparable
①使用空参构造创建TreeSet集合
②自定义的Student类实现Comparable接口
③重写里面的compareTo方法
例子:按年龄,如果年龄一样按名字,如果名字也一样就是同一个人不存
Student类
public class Student implements Comparable<Student>{
private int age;
private String name;
//getter setter 构造方法
@Override
public int compareTo(Student o) {
//按照对象年龄进行排序
//如果返回值是负数表示当前存入的元素较小,存左边
//返回值是0说明当前存入的元素重复,不存
//this:当前存的元素
//o:已经存的元素
int result=this.age-o.age;
result=result==0?this.name.compareTo(o.getName()):result;
return result;
}
}
主方法
public class MyTreeSet1 {
public static void main(String[] args) {
TreeSet<Student> ts=new TreeSet<>();
Student s1=new Student("A",15);
Student s2=new Student("b",12);
Student s3=new Student("c",19);
Student s4=new Student("d",19);
ts.add(s1);
ts.add(s2);
ts.add(s3);
System.out.println(ts);
}
}
2.比较器排序Comparator的使用
TreeSet的带参构造方法使用的是比较器排序对元素进行排序,比较器排序就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法。重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
例子
Teacher类
public class Teacher{
private int age;
private String name;
//getter setter 构造方法
}
主方法
public class MyTreeSet2 {
public static void main(String[] args) {
TreeSet<Teacher> ts=new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
//o1 表示现在要存入的那个元素
//o2 表示已经存入到集合中的元素
int result=o1.getAge()-o2.getAge();
result=result==0?o1.getName().compareTo(o2.getName()):result;
return result;
}
});
Teacher t1=new Teacher("A",15);
Teacher t2=new Teacher("B",12);
Teacher t3=new Teacher("C",19);
Teacher t4=new Teacher("D",19);
ts.add(t1);
ts.add(t2);
ts.add(t3);
ts.add(t4);
}
}
两种排序方式比较
自然排序:自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
比较器排序:创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,使用比较器排序
TODO:红黑树
实在听不懂回头再补
HashSet
JDK8之前:数组+链表
JDK8之后:数组+链表+红黑树
特点:
1.底层数据结构是哈希表
2.不能保证存储和取出的顺序完全一致
3.没有带索引的方法,所以不能使用普通for循环遍历
4.由于是Set集合所以元素唯一
哈希值:是JDK根据对象的地址或者属性值,算出来的int类型的整数
Object类中有一个方法可以获取对象的哈希值
public int hashCode():根据对象的地址值计算出来的哈希值
如果没有重写hashCode方法,那么根据对象的地址值计算哈希值,不同对象的哈希值是不一样的,同一个对象多次调用hashCode()方法返回的哈希值是相同的。
如果重写了hashCode方法,一般通过对象的属性计算出哈希值。如果不同的对象属性值一样,那么计算出来的哈希值也是一样的
day11-07 Map
interface Map<K,V>
K:键的数据类型
V:值的数据类型
键不能重复,值可以重复。键和值是一一对应的,每个键只能找到自己对应的值
基本功能:
V put(K key,V value):添加元素
V remove(Object key):根据键删除键值对元素
void clear():移除所有的键值对元素
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
int size():集合的长度(集合中键值对的个数)
遍历:
1.keyset():获取所有的键的集合
2.entrySet():获取所有键值对对象的集合
HashMap
底层是哈希表结构,依赖hashCode方法和equals方法保证键的唯一
遍历:
12同Map
3.hm.forEach(
(Student key,String value)->{
System.out.println(key+“—”+value);
}
);
TreeMap
底层是红黑树结构,依赖自然排序或比较器排序对键进行排序,如果键存储的是自定义对象则需要实现Comparable接口或在创建TreeMap对象时给出比较器排序规则
day11-15 可变参数
可变参数
形参的个数是可以变化的
格式:修饰符 返回值类型 方法名(数据类型…变量名){}
例子:public static int sum(int…a);
不可变集合
of方法可以创建一个不可变的集合,这个集合不能添加,不能删除,不能修改,但是可以结合集合的带参构造,实现集合的批量添加。
static <E> List<E> of(E…elements) :创建一个具有指定元素的List集合对象
staitc <E> Set<E> of(E…elements) : 创建一个具有指定元素的Set集合对象
static <K,V> Map<K,V> of(E…elements) :创建一个具有指定元素的Map集合对象
例子:
List<String> list=List.of(“a”,“b”,“c”,“d”);
Set<String> set=Set.of(“a”,“b”,“c”,“d”);//不能有重复元素
Map<String> map=Map.of(“a”,“b”,“c”,“d”);//k1,v1,k2,v2
可以用来初始化
初始化List
ArrayList<String> list=new ArrayList<>(List.of(“a”,“b”,“c”,“d”));
说明:
首先通过调用List.of方法来创建一个不可变的集合,of方法的形参就是一个可变参数
再创建一个ArrayList集合,并把这个不可变的集合中所有的数据都添加到ArrayList中
初始化Map
Map<String,String> map=Map.of(“AAA”,“aaa”,“BBB”,“bbb”);
Map<String,String> map=Map.ofEntries(Map.entry(“AAA”,"bbb),Map.entry(“BBB”,“bbb”));
day12-01 Stream流
使用场景:
1.单列集合
可以使用Collection接口中的默认方法strean()生成流
default Stream<E> stream()
2.双列集合
间接的生成流
可以先通过keySet或者entrySet获取一个Set集合,再获取Stream流
3.数组
Arrays中的静态方法stream生成流
4.同种数据类型的多个数据
使用Stream.of(T…value)生成流
//1.单列集合
ArrayList<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.stream().forEach(s-> System.out.println(s));
//2.双列集合
HashMap<String,Integer> hm=new HashMap<>();
hm.put("zhangsan",23);
hm.put("lisi",24);
hm.put("wangwu",25);
hm.put("zhaoliu",26);
hm.put("qianqi",27);
//keyset先获取到所有的键,再把这个Set集合中所有的键放到stream流中
hm.keySet().stream().forEach(s-> System.out.println(s));
//entrySet先获取到所有的键值对对象,再把这个Set集合中所有的键值对对象放到Stream流中
hm.entrySet().stream().forEach(s-> System.out.println(s));
//3.数组
int[] arr={1,2,3,4,5};
Arrays.stream(arr).forEach(s-> System.out.println(s));
//4.同种数据类型的多个数据
Stream.of(1,2,3,4,5,6,7,8).forEach(s-> System.out.println(s));
Stream流常见中间操作方法
1.fliter
filter方法获取流中的每一个数据,而test方法中的s就依次表示流中的每一个数据,我们只要在test方法中对s进行判断就可以了。如果判断结果为true则当前数据留下,如果判断的结果为false,则当前数据不要
因为Predicate接口中只有一个抽象方法test,所以我们可以使用lambda表达式来简化
List<String> list=new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
// 匿名内部类
list.stream().filter(new Predicate<String>(){
@Override
public boolean test(String s){
boolean result=s.startsWith("张");
return result;
}
}).forEach(s->System.out.println(s));
// lambda
list.stream().filter((String s)->{
boolean result=s.startsWith("张");
return result;
}).forEach(s->System.out.println(s));
// lambda简写
list.stream().filter(s->s.startsWith("张")).forEach(s->System.out.println(s));
2.Stream\<T\> limit(long maxSize):截取指定参数个数的数据
3.Stream\<T\> skip(long n):跳过指定参数个数的数据
4.static\<T\> Stream\<T\> concat(Stream a,Stream b):合并a和b两个流为一个流
5.Stream\<T\> disctinct():去除流中重复的元素,依赖hashCode和equals方法
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤","谢广坤"));
//limit,截取保留前面的数据
list.stream().limit(2).forEach(s-> System.out.println(s));
//skip,跳过前面的保留后面的
list.stream().skip(2).forEach(s-> System.out.println(s));
//concat
ArrayList<String> list2=new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤"));
Stream<String> stream1=list2.stream();
Stream<String> stream2=list2.stream();
Stream.concat(stream1,stream2).forEach(s-> System.out.println(s));//list1内容,list2内容
//distinct
list.stream().distinct().forEach(s-> System.out.println(s));
}
Stream流常见终结操作方法
1.void forEach(Consumer action):对此流的每个元素执行操作
Consumer接口中的方法 : void accept(T t):对给定的参数执行此操作
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>(List.of("张三丰","张无忌","张翠山","王二麻子","张良","谢广坤","谢广坤"));
//在forEach方法的底层会循环获取到流中的每一个数据,并循环调用accept方法,并把每一个数据传递给accept方法
//s就依次表示了流中的每一个数据,所以只要在accept方法中写上处理的业务逻辑就可以了
//匿名内部类方法
list.stream().forEach(
new Consumer<String>() {
@Override
public void accept(String s) {
System.out.println(s);
}
}
);
//lambda,因为Comsumer接口中,只有一个accept方法
list.stream().forEach(s-> System.out.println(s));
}
2.long count():返回此流中的元素数
//count
long count=list.stream().count();
System.out.println(count);
Stream流的收集操作
public static void main(String[] args) {
ArrayList<Integer> list=new ArrayList<>();
for(int i=0;i<=10;i++){
list.add(i);
}
list.stream().filter(s->s%2==0).forEach(s-> System.out.println(s));//偶数
list.stream().forEach(s-> System.out.println(s));//1~10
}
结论:在Stream流中无法直接修改集合、数组等数据源中的数据
收集操作:
R collect(Collector collector)
工具类Collectors提供了具体的收集方式
1.public static <T> Collector toList():把元素收集到List集合中
2.public static <T> Collector toSet():把元素收集到Set集合中
3.public static Collector toMap(Function keyMapper,Function valueMapper):把元素收集到Mapper集合中
public static void main(String[] args) {
ArrayList<Integer> list1=new ArrayList<>();
for (int i = 1; i <=10 ; i++) {
list1.add(i);
}
list1.add(10);
//filter负责过滤数据,collect负责获取流中剩余的数据,但是它不负责创建容器,也不负责把数据添加到容器中
//Collectors.toList():在底层会创建一个List集合,并把所有的数据添加到List集合中
List<Integer> list = list1.stream().filter(s -> s % 2 == 0).collect(Collectors.toList());
System.out.println(list);//[2, 4, 6, 8, 10, 10]
Set<Integer> set = list1.stream().filter(s -> s % 2 == 0).collect(Collectors.toSet());
System.out.println(set);//[2, 4, 6, 8, 10]
}
day12-10 File
构造方法
File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent,String child):从父路径名字符串和子路径名字符串创建新的File实例
File(File parent,String child):从父抽象路径名和子路径名字符串创建新的File实例
public static void main(String[] args) {
//File(String pathname):通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
String path="D:\\java\\21heima\\src\\filedemo\\a.txt";
File file1=new File(path);
System.out.println(file1);
//File(String parent,String child):从父路径名字符串和子路径名字符串创建新的File实例
String path1="D:\\java\\21heima\\src\\filedemo";
String path2="b.txt";
File file2=new File(path1,path2);
System.out.println(file2);
//File(File parent,String child):从父抽象路径名和子路径名字符串创建新的File实例
File file3=new File("D:\\java\\21heima\\src\\filedemo");
String path3="c.txt";
File file=new File(file3,path3);
System.out.println(file3);
}
绝对路径和相对路径
绝对路径:从盘符开始 D:\java\21heima\src\filedemo\a.txt
相对路径:相对当前项目下的路径 “模块名\a.txt”
File类创建功能
public booloean createNewFile():创建一个新的空的文件
注意:1.如果文件存在,则创建失败,返回false
2.如果文件不存在,则创建成功,返回true
3.不管调用者有没有后缀名,只能创建文件
public boolean mkdir():创建一个单级文件夹
注意:1.只能创建单级文件夹,不能创建多级文件夹
2. 不管调用者有没有后缀名,只能创建单击文件夹
public boolean mkdirs():创建一个多级文件夹
注意:1.可以创建单击文件夹,也可以创建多级文件夹
2.不管调用者有没有后缀名,只能创建文件夹
所以mkdir()确实没啥用,mkdirs()底层调用的mkdir()
File类删除功能
public boolean delete():删除由此抽象路径名表示的文件或目录
注意:
1.不走回收站
2.如果删除的是文件则直接删除,如果删除的是文件夹,则只能删除空文件夹
3.如果要删除一个有内容的文件夹,只能先进入这个文件夹,把里面的东西删光,才能删这个文件夹
//删文件
File file=new File("D:\\java\\21heima\\src\\filedemo\\a.txt");
boolean result=file.delete();
System.out.println(result);
//删文件夹
File file=new File("D:\\java\\21heima\\test");
boolean result=file.delete();
System.out.println(result);
File类判断和获取功能
public boolean isDirectory():测试此抽象路径名表示的File是否为目录
public boolean isFile():测试此抽象路径名表示的File是否为文件
public boolean exists():测试此抽象路径名表示的File是否存在
public String getName():返回由此抽象路径名表示的文件或目录的名称
注意:1.如果调用者是文件那么获取的是文件名和后缀名
2.如果调用者是一个文件夹那么获取的是文件夹的名字
File类高级获取功能
public File[] listFiles():返回此抽象路径名表示的目录中的文件和目录的File对象数组
注意:1.当调用者是一个文件或不存在时,方法返回一个null
2.当调用者是一个文件夹时,方法返回一个长度为0的数组
3.当调用者是一个有内容的文件夹时,方法获取文件夹下所有文件和文件夹,包含隐藏
4.当文件夹是一个有权限才能进入的文件夹,返回的是null
两个File方法练习例子
1.创建一个文件 2.删除一个多级文件夹3.统计某文件夹下所有类型文件数量(这个没记,懒了)
public static void main(String[] args) throws IOException {
//例子1:创建一个文件
File file=new File("src\\filedemo\\aaa");
//注意点:文件所在的文件夹必须要存在,
if(!file.exists()){
//如果文件夹不存在就创建
file.mkdirs();
}
File newFile=new File(file,"a.txt");
newFile.createNewFile();
//例子2.删除一个多级文件夹
File src=new File("src\\filedemo\\aaa");
deleteDir(src);
}
private static void deleteDir(File src) {
//删除文件夹里所有内容
File[] files = src.listFiles();
for (File file : files) {
if(file.isFile()){
file.delete();
}else{
deleteDir(file);
}
}
//删除这个文件夹
src.delete();
}
本文深入讲解Java集合框架的核心概念,包括泛型、Set接口及其实现类如TreeSet和HashSet的特点与使用方法,同时介绍了Map接口及其应用,还探讨了可变参数、Stream流的操作方法以及File类的基本用法。
2468

被折叠的 条评论
为什么被折叠?



