第六次实验室周报

博客主要介绍了Java集合相关知识,如TreeSet底层用红黑树算法可排序,使用时元素需同类型,可通过实现Comparable或Comparator接口实现排序;还介绍了Map的几种实现类。此外,提到集合工具类及泛型的作用。最后讲解了Java中文件操作,如File类表示文件和目录,不同系统路径表示和分割方式不同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从上次集合讲起

TreeSet :Set接口有一个实现类:TreeSet类,该类底层使用红黑树算法(平衡二叉树)。
可以对集合中的数据按照一定的规则来排序。

public static void main(String[] args) {
        // 元素可以自动排序
        Set set=new TreeSet();
        set.add(10);
        set.add(5);
        set.add(0);
        System.out.println(set);

        set=new TreeSet();
        set.add("5");
        set.add("10");
        set.add("2");
        set.add("5");
        set.add("高数");
        set.add("线代");
        set.add("离散");
        System.out.println(set);// 结果:10, 2, 5, 离散, 线代, 高数 。 为什么10是第一位呢?因为是字符串,会先比较10中的1.

注意:使用TreeSet,一定要保证该集合中的元素必须是同一种数据类型。
只有同一种数据类型才有可比性,若数据类型不同,就会报错。

把某一对象存储在TreeSet中,对象的类通过实现Comparable接口才会具有可比性,否则报错(类型转换错误)。

第一种方法继承Comparable接口:

Comparable 接口:
方法:
public int compareTo( Object o ){
编写比较规则
}

拿当前对象(this)和传入的o对象作比较。
返回: 当前对象 > o : return 正整数;
当前对象 == o : return 0;
当前对象 < o : return 负整数;
TreeSet会认为,如果compareTo方法返回的是0,则认为是同一个对象,若是同一个对象则不会添加到集合中。

class Student1 implements Comparable{
       private String name;
       private int    age;
       private int    score;

    public Student1(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }

    // 作比较
    @Override
    public int compareTo(Object obj) { // 父类要访问对象的成员变量,必须强转成子类
        Student1 other=(Student1)obj;
        if(this.score > other.score){
            return 1;
        }else if(this.score < other.score){
            return -1;
        }else{  // 如果成绩相同时则比较年龄
            if(this.age > other.age){
                return 1;
            }else if(this.age < other.age){
                return -1;
            }else{
                return this.name.compareTo(other.name); // 年龄和成绩都相同时,比较名字(String已实现compareTo方法)
            }
        }
    }

    @Override
    public String toString() {
        return "Studen1[name = "+name+",age = "+age+",score = "+score+"]";
    }
}

^父类要访问对象的成员变量,必须强转成子类。

第二种方法继承Comparator接口:

//根据名字长度来排序,长的先排出来,短的后排出来
class Teacher {
    private String name;
    public Teacher(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                '}';
    }
}

public class StudentSortDemo2 {
    public static void main(String[] args) {
        Comparator com=new NameCom();// 不用Comparable接口的原因是,其采用的是自然排序(从低到高)。Comparator 更多是自定义排序(例如名字有长短之分)
        Set set=new TreeSet(com);// com就相当于承载了你的自定义规则,并且给了TreeSet
        /*Set set=new TreeSet(new Comparator() {--------------->匿名内部类的方法
            @Override
            public int compare(Object o1, Object o2) {
                Teacher t1=(Teacher)o1;
                Teacher t2=(Teacher)o2;
                String name1=t1.getName();
                String name2=t2.getName();
                if(name1.length() > name2.length()){
                    return -1;
                }else if(name1.length() < name2.length()){
                    return 1;
                }
                return 0;
            }
        });*/
        set.add(new Teacher("will"));
        set.add(new Teacher("ajksjdhbk"));
        set.add(new Teacher("MA"));
        System.out.println(set);
    }
}

class NameCom implements Comparator{
    @Override
    public int compare(Object o1, Object o2) {
        Teacher t1=(Teacher)o1;
        Teacher t2=(Teacher)o2;
        String name1=t1.getName();
        String name2=t2.getName();
        if(name1.length() > name2.length()){
            return -1;
        }else if(name1.length() < name2.length()){
            return 1;
        }
        return 0;
    }
}

^不用Comparable接口的原因是,其采用的是自然排序(从低到高)。Comparator 更多是自定义排序(例如名字有长短之分)。

TreeSet里面应用的排序规则( Comparable和Comparator接口 ):
Comparable:自然顺序排序(低–>高):内比较器
比较Set集合中是否是同一个元素的标准。
compareTo方法是否返回0。
Comparator:自定义排序 : 外比较器
比较Set集合中是否是同一个元素的标准。
compare方法是否返回0.
之前欠下的集合继承体系图

Map不是集合!
Map表示一种映射关系:
数学中的定义:有A和B两个集合,A集合中的一个元素,总能在B集合中找到唯一的一个映射值。(B集合中的一个元素,可以被A集合中的多个元素映射)。
Map:多个Entry的集合,一个Entry表示一个键值对,Map表示多个键值对,Map表示多组映射关系。

Map接口对应常用的实现类
Hashtable类:在没有集合框架之前,就使用Hashtable来表示映射关系。现在建议使用HashMap类。通过源码可以看出,Hashtable中的每一个方法都是用synchronized修饰。

HashMap类:底层使用哈希表算法。底层没有用synchronized修饰。
HashMap相对于Hashtable来说,性能较高,但安全性较低。与ArrayList和Vector的区别相同。

LinkedHashMap类:保证Map中的key会记录添加顺序。
TreeMap类:保证Map中的key会按照指定的规则来排序。

通过观察Set和Map的体系,会发现很多实现类的名字相似(底层算法相同)。HashSet的底层就是使用HashMap。
在构建HashSet对象时,底层创建的是一个HashMap对象。
在把元素添加到set时,底层是存放在Map中的。
Map中的key其实就是Set的元素。
Map中所有的key其实就是Set集合。
在这里插入图片描述

集合工具类
1:java.util.Arrays类:
Public static List asList(Object… params):把一个数组转换成对应的List集合。
数组转换为List最便捷的方式:List Arrays.asList( Object… params ):其底层还是ArrayList,不过是其内部类。
注意:返回的List的长度是固定的,不能改变。不过,一旦转换成功,该集合就会定长,所以对list进行增加删减操作就会报错,但替换操作不会。

2:java.util.Collections类:操作集合的工具类。
ArrayList,HashSet,HashMap都是线程不安全的类。

// 得到一个线程安全的Set
Set set=Collections.synchronizedSet(new HashSet<>());
synchronized (set){
    // 对set对象的一些操作
}

但是我们平时不经常用,直接在Set方法上加入synchronized就行。
Collections的一些操作:

//返回空集:没有元素的集合
        List emptyList= Collections.EMPTY_LIST; // 常量
        System.out.println(emptyList);
        emptyList =Collections.emptyList();//方法
        System.out.println(emptyList);

        list=Arrays.asList(1,2,3,4,5,6);
        int index=Collections.binarySearch(list,5);//用二分法查找list中的元素,返回索引
        System.out.println(index);
        System.out.println(list);
        Collections.reverse(list);//对list里的元素从后往前翻转
        System.out.println(list);
        Collections.shuffle(list);//对list里的元素进行随机翻转
        System.out.println(list);

使用集合但不使用泛型所带来的问题:
1、编译器存在警告。
2、使用Tree类,如何保证只存储同一种数据类型(不是自己主动要求的那种类型)。
3、从集合中取出元素必须强转(或者使用Object)。
泛型:简概为广泛的通用类型,可以实现不同的调用者使用不同的数据类型。
若泛型不指明,就默认为Object类。
解决问题二:例如,想让TreeSet只存储String类型的元素:

Set<String> set = new TreeSet<String>();或Set<String> set = new TreeSet<>();

泛型通配符 :? ------------不知道传什么类型。

public static void main(String[] args) {
        // 泛型通配符 :? ------------不知道传什么类型
        List<Object> list1=null;
        List<Number> list2=null;
        List<Integer> list3=null;
        //dowork(list1); 该操作会报错,因为此时在限定泛型上限只接受 Number和其子类
        dowork(list2);
        dowork(list3);

        dowork1(list1);
        dowork1(list2);
        //dowork1(list3); 该操作会报错,因为此时在限定泛型下限限只接受 Number和其父类
    }
    static void dowork(List<? extends Number> list){ // 限定了泛型上限

    }
    static void dowork1(List<? super Number> list){ // 限定了泛型下限

    }

文件

I/O的类库都在java.io包中。---------->使用I/O的类库必须使用import引入。

Java . io . File类:表示了文件和目录。
Windows系统:表示路径使用\ 。
但是在java中,一根 \ 表示转义符,我们必须写成: \。
路径分割使用 ; 。
Unix 系统:表示路径使用/ ,但是windows也可以用。
路径分割使用 : 。
注意:File表示一个文件/一个文件夹的路径,一旦File对象创建成功,就只能表示指定的路径。

public static void main(String[] args) throws IOException {
        //创建File对象(使用前三个构造器)
        File f1=new File("E:/hello/read.txt");
        // 判断文件是文件夹(目录)还是文件
        if(f1.isDirectory()){
            System.out.println("是目录");
        }
        if(f1.isFile()){
            System.out.println("是文件");
        }
        //boolean exists()测试此抽象路径名表示的文件或目录是否存在。
        System.out.println(f1.exists());

         // 创建文件夹
       new File("E:/hello/read1.txt").createNewFile();//文件不存在时
        new File("E:/hello/t").mkdir();// 目录存在,尾目录不存在
        new File("E:/hello1/t1").mkdirs();//创建多级目录
       
        
        File f1=new File("E:/hello/read.txt");
        File f2=new File("E:/hello","read.txt");
        //                         路径名           文档名

        //使用File表示文件夹对象
        File dir=new File("E:/hello");
        File f3=new File(dir,"read.txt");
        

        //获取文件名称
        String fileName=f1.getName();
        System.out.println(fileName);
        //获取文件父目录
        String dir=f1.getParent();
        System.out.println(dir);
        //获取文件的路径(相对路径):一般在该项目中找,够用
        System.out.println(f1.getPath());
        // 获取文件的绝对路径:不在项目中找,就要用这个
        System.out.println(f1.getAbsolutePath());
        // 获取最后一次修改时间
        System.out.println(f1.lastModified());
        //修改文件名:boolean renameTo(File dest)重新命名此抽象路径名表示的文件。
        f1.renameTo(new File("E:/hello/reads.txt"));
    }

获取当前目录的子文件:

//获取当前目录的子文件
public class FileDemo2 {
    public static void main(String[] args) {
        File file=new File("E:\\BaiduNetdiskDownload");
        File[] fs=file.listFiles();
        for(File f : fs){
            System.out.println(f);
        }
        System.out.println("--------------------------------------------------------");
        //使用递归:获取该目录下的所有文件以及子目录的所有文件
        //listAllFiles(file);

        //列出有哪些盘符
        File[] roots=file.listRoots();
        for(File f : roots){
            System.out.println(f);
        }
    }
    public static void listAllFiles(File file){
        System.out.println(file);
        if(file.isDirectory()) {
            File[] fs = file.listFiles();
            for( File files : fs){
                listAllFiles(files);
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值