Java基础 (二)

发布于:2025-02-11 ⋅ 阅读:(104) ⋅ 点赞:(0)

集合

在这里插入图片描述

单列集合 List、Set

List

在这里插入图片描述

在这里插入图片描述


ArrayList<Integer> list = new ArrayList<> ();
   // 添加元素
   list.add (1);
   list.add (2);
   list.add (5);
   list.add (6);
   System.out.println (list);
   // 移除 index = 1 的元素
   list.remove (1);
   System.out.println (list);
   // 判断是否包含某个元素
   boolean contains = list.contains (6);
   System.out.println (contains);
   // 获取元素的个数
   int size = list.size ();
   System.out.println (size);
   // 判断是否为空
   boolean isEmpty = list.isEmpty ();
   System.out.println (isEmpty);
   //  获取 index = 1 的元素
   Integer res = list.get (1);
   System.out.println (res);
   // 清空 list
   list.clear ();
   System.out.println (list);


在这里插入图片描述

Set

在这里插入图片描述

HashSet

/**
  * Set集合是一种 不允许有重复元素的集合
  *    无序的
  *    无索引
  *    不能有重复元素
  *    允许有一个null
  */
 HashSet<Integer> set = new HashSet<> ();
 set.add (1);
 set.add (2);
 set.add (null);
 set.add (2);
 set.add (3);
 set.add (4);
 // 打印Set集合
 System.out.println (set);
 int size = set.size ();
 // 打印Set集合的大小
 System.out.println (size);

 boolean empty = set.isEmpty ();
 // 打印Set集合是否为空
 System.out.println (empty);
 boolean contains = set.contains (1);
 System.out.println (contains);
 // 移除指定元素
 set.remove (1);
 System.out.println (set);
 // 清空Set集合
 set.clear ();

LinkedHashSet

在这里插入图片描述

TreeSet

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


/**
 * 降序
 */
 
TreeSet<Integer> ts = new TreeSet<> ((o1, o2) -> o2 - o1);
ts.add (1);
ts.add (5);
ts.add (3);
ts.add (4);
ts.add (2);
System.out.println (ts);
for (Integer t : ts) {
    System.out.print (t+" ");
}

两种 排序方式

在这里插入图片描述

public class User implements Comparable<User> {
    private String name;
    private int age;

    public User() {
    }

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


    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "User{name = " + name + ", age = " + age + "}";
    }

    @Override
    public int compareTo(User o) {
        // 按照年龄 升序
        return this.getAge () - o.getAge ();
    }

}

TreeSet<User> ts = new TreeSet<> ();

ts.add (new User ("zhangsan",18));
ts.add (new User ("lisi",19));
ts.add (new User ("wangwu",20));
for (User user : ts) {
    System.out.println (user);
}

在这里插入图片描述

// 可以使用 Lambda表达式简化
TreeSet<User> ts = new TreeSet<> (new Comparator<User> () {
    @Override
    public int compare(User u1, User u2) {
        // 降序
        return u2.getAge () - u1.getAge ();
    }
});

ts.add (new User ("zhangsan", 18));
ts.add (new User ("lisi", 19));
ts.add (new User ("wangwu", 20));
for (User user : ts) {
    System.out.println (user);
}

在这里插入图片描述

双列集合 Map

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

HashMap

在这里插入图片描述

在这里插入图片描述
存 自定义对象需重写
不需要

// HashMap 无序
        // 可存储自定义对象
        HashMap<String, Integer> map = new HashMap<> ();
        // 添加元素 put
        map.put ("小米", 2000);
        map.put ("华为", 3000);
        map.put ("苹果", 5000);
        System.out.println (map);

        /**
         * 键 不存在,直接添加键值对
         * 键 存在,覆盖
         */
        map.put ("苹果", 6000);
        System.out.println (map);


        // putIfAbsent 不存在键时,才添加
        map.putIfAbsent ("小米", 1000);
        System.out.println (map);

        // 获取键对应的值,不存在 返回null
        Integer huawei = map.get ("华为");
        System.out.println ("华为价格:" + huawei);
        Integer huaweiS = map.get ("华为s");
        System.out.println ("华为s价格:" + huaweiS);

        // 获取键对应的值,不存在 返回默认值
        Integer huaweiS2 = map.getOrDefault ("华为s", 9999);
        System.out.println ("华为s价格:" + huaweiS2);

        System.out.println ("=========================");
        /**
         * 获取 键值对集合 来遍历map
         */
        Set<Map.Entry<String, Integer>> entries = map.entrySet ();
        for (Map.Entry<String, Integer> entry : entries) {
            String key = entry.getKey ();
            Integer value = entry.getValue ();
            System.out.println (key + " " + value);
        }
        System.out.println ("=========================");
        /**
         * 获取所有的键
         */

        Set<String> keySet = map.keySet ();
        for (String key : keySet) {
            Integer val = map.get (key);
            System.out.println (key + " " + val);
        }
        System.out.println ("=========================");


        /**
         *  Lambda表达式 遍历map
         */
        map.forEach ((k, v) -> {
            System.out.println (k + " " + v);
        });
        System.out.println ("=========================");

        // 删除键值对,返回值是 键对应的值
        Integer val = map.remove ("小米");
        System.out.println (val);
        System.out.println (map);
        System.out.println ("=========================");
        // 判断键是否存在
        boolean keyHua = map.containsKey ("华为");
        boolean keyXm = map.containsKey ("小米");
        System.out.println ("华为:" + keyHua + " " + "小米:" + keyXm);
        System.out.println ("=========================");
        // 判断值是否存在
        boolean containsValue = map.containsValue (1000);
        System.out.println ("值是否存在:" + containsValue);
        System.out.println ("=========================");
        // 判断是否为空
        boolean empty = map.isEmpty ();
        System.out.println ("map为空:" + empty);
        System.out.println ("=========================");

        // 集合大小
        int size = map.size ();
        System.out.println ("集合大小:" + size);
        System.out.println ("=========================");
        // 清空集合
        map.clear ();

HashMap 练习



/**
 * 80 名学生,进行秋游
 * 四个景点
 *  A B C D
 * 每个学生只能选择一个景点
 * 统计最终哪个景点想去的人数最多
 */
String[] arr = {"A", "B", "C", "D"};
Random r = new Random ();
HashMap<String, Integer> map = new HashMap<> ();
for (int i = 0; i < 80; i++) {
    int idx = r.nextInt (4);
    // 获取随机景点
    String name = arr[idx];
    // 在原有的基础上+1
    map.put (name, map.getOrDefault (name, 0) + 1);

}
Set<String> keySet = map.keySet ();
// 记录结果
int max = 0;
String name = "";
for (String key : keySet) {
    Integer val = map.get (key);
    if (val > max) {
        max = val;
        name = key;
    }

}
System.out.println (name + " " + max);
System.out.println (map);


LinkedHashMap

在这里插入图片描述

在这里插入图片描述

        LinkedHashMap<String , Integer> map = new LinkedHashMap<> ();
        map.put ("c", 1);
        map.put ("a", 2);
        map.put ("b", 3);
        map.put ("d", 4);
        System.out.println (map);

在这里插入图片描述

TreeMap

在这里插入图片描述

       /**
         * 按照字符串长度 降序排序
         */
        TreeMap<String, Integer> map = new TreeMap<> ((o1, o2) -> o2.length () - o1.length ());
        map.put ("a", 1);
        map.put ("dd", 4);
        map.put ("edw", 5);
        map.put ("dwda", 3);
        System.out.println (map);

在这里插入图片描述

练习1 不重复的随机点名


    /**
     * 班级里有5个学生
     * 要求:
     * 被点到的学生,不能再被点到
     * 如果所有的学生都被点到了,需要重新开启第二轮点名
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        ArrayList<String> list = new ArrayList<> ();
        Collections.addAll (list, "张三", "李四", "王五", "赵六", "钱七");

        // 记录被点到的学生
        ArrayList<String> list1 = new ArrayList<> ();
        // 开启点名,10次
        Random random = new Random ();
        for (int i = 0; i < 10; i++) {
            // 随机获取一个下标,范围是[0,集合的长度)
            // size 会随着集合的变化而变化
            int index = random.nextInt (list.size ());
            // 根据下标,从集合中删除一个元素,返回被删除的元素
            // 根据元素,删除集合中的元素,返回删除是否成功 boolean
            String s = list.remove (index);
            list1.add (s);
            System.out.println (s);
            // 如果集合中没有元素了,需要重新开启第二轮点名
            if (list.size () == 0) {
                list.addAll (list1);
                list1.clear ();
                System.out.println ("---------------------------");
            }


        }


    }

在这里插入图片描述

练习2 集合嵌套


 public static void main(String[] args) throws Exception {
        test1 ();
    }

    /**
     * 将省份和市 使用Map集合存储
     * 遍历Map集合
     */
    private static void test1() {
    // 值还是一个 List
        Map<String, List<String>> map = new HashMap<String, List<String>> ();
        ArrayList<String> list1 = new ArrayList<> ();
        Collections.addAll (list1, "石家庄市", "唐山市", "秦皇岛市", "邯郸市", "邢台市");
        map.put ("河北省", list1);
        ArrayList<String> list2 = new ArrayList<> ();
        Collections.addAll (list2, "太原市", "大同市", "阳泉市", "长治市", "晋城市");
        map.put ("山西省", list2);
        ArrayList<String> list3 = new ArrayList<> ();
        Collections.addAll (list3, "沈阳市", "大连市", "鞍山市", "抚顺市", "本溪市");
        map.put ("辽宁省", list3);

        //遍历map集合,获取键值对的方式
        for (Map.Entry<String, List<String>> entry : map.entrySet ()) {
            String key = entry.getKey ();
            String val = "";
            List<String> value = entry.getValue ();
            for (int i = 0; i < value.size (); i++) {
                val += value.get (i);
                // 如果是最后一个元素就不加逗号
                // 不加逗号很难直接实现,转为 不是最后一个元素就加逗号
                if (i != value.size () - 1) {
                    val += ",";
                }

            }
            System.out.println (key + "=" + val);
        }
    }

File

创建对象

在这里插入图片描述


    /**
     * \: 表示转义字符
     * \\: 表示一个普通的反斜杠
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        // 通过文件路径获取文件对象
        String path = "C:\\Users\\Administrator\\Desktop\\a.txt";
        File file1 = new File (path);
        System.out.println (file1);

        // 通过父路径和子路径获取文件对象
        String parent = "C:\\Users\\Administrator\\Desktop";
        String child = "a.txt";
        File file2 = new File (parent, child);
        System.out.println (file2);
        // \\: 表示一个普通的反斜杠
        // \: 表示转义字符
        File file3 = new File (parent + "\\" + child);
        System.out.println (file3);

        file1.delete ();

    }

成员方法

判断、获取

在这里插入图片描述


     // 通过文件路径获取文件对象
        String path = "C:\\Users\\Administrator\\Desktop\\a.txt";
        File file1 = new File (path);
        boolean exists = file1.exists ();
        if (exists) {
            System.out.println ("文件存在");
            // 文件大小
            System.out.println (file1.length ());
            // 文件名称
            System.out.println (file1.getName ());
            // 文件路径
            System.out.println (file1.getPath ());
            // 绝对路径
            System.out.println (file1.getAbsolutePath ());
            // 最后修改时间
            long lastModified = file1.lastModified ();
            Date date = new Date (lastModified);
            System.out.println (date);
            // 是否是文件
            System.out.println (file1.isFile ());
            // 是否是文件夹
            System.out.println (file1.isDirectory ());
            // 是否隐藏
            System.out.println (file1.isHidden ());
            // 是否可读
            System.out.println (file1.canRead ());
            // 是否可写
            System.out.println (file1.canWrite ());
            // 是否可执行
            System.out.println (file1.canExecute ());
            // 父级路径
            System.out.println (file1.getParent ());

        }


创建、删除

在这里插入图片描述

    public static void main(String[] args) throws Exception {

        // 通过文件路径获取文件对象
        String path = "C:\\Users\\Administrator\\Desktop\\b.txt";
        File file1 = new File (path);


        // 创建文件,需要父级目录存在,否则创建失败
        /**
         * Exception in thread "main" java.io.IOException: 系统找不到指定的路径。
         */
        boolean newFile = file1.createNewFile ();
        System.out.println (newFile);
        System.out.println ("--------------");
        /**
         * 创建多级目录
         * mkdirs:创建多级目录
         * mkdir:创建一级目录
         */
        boolean mkdirs = new File ("D:\\a\\b\\c").mkdirs ();
        System.out.println (mkdirs);

        /**
         * 删除文件或者文件夹
         * delete:删除文件或者文件夹
         * 注意:
         * 1.如果删除的是文件夹,那么文件夹必须是空的,否则删除失败
         * 2.如果删除的是文件,那么文件必须 存在,否则删除失败
         * 3.如果删除的是文件夹,那么文件夹必须存在,否则删除失败
         *
         */
        boolean delete = file1.delete ();
        System.out.println (delete);
        System.out.println ("--------------");

        deleteDir (new File ("D:\\a"));
    }

    /**
     * 递归删除文件夹
     */
    public static void deleteDir(File dir) {
        // 获取文件夹下的 所有文件或者文件夹
        File[] files = dir.listFiles ();
        // 遍历文件夹下的所有文件或者文件夹
        for (File file : files) {
            // 判断当前遍历的是文件还是文件夹
            if (file.isFile ()) {
                // 如果是文件,直接删除
                file.delete ();
            } else {
                // 如果是文件夹,递归删除
                deleteDir (file);
            }
        }
        // 删除文件夹
        dir.delete ();
    }


练习

查找一个文件夹中,有没有avi文件


    public static void main(String[] args) throws Exception {

        File file = new File ("D:\\aaa");
        boolean haveAvi = haveAvi (file);
        System.out.println (haveAvi);

    }

    /**
     * 查找一个文件夹中,有没有avi文件
     *
     * @param f
     * @return
     */
    public static boolean haveAvi(File f) {
        // 获取文件列表
        File[] files = f.listFiles ();
        for (File file : files) {
            // 判断是否是文件
            // 判断是否是avi文件
            if (file.isFile () && file.getName ().endsWith (".avi")) {
                return true;
            }
        }
        // 如果没有找到,返回false
        return false;

    }

统计一个文件中每种文件的个数,并且打印(考虑子文件夹)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

    /**
     * 统计一个文件中每种文件的个数,并且打印(考虑子文件夹)
     * 打印格式如下:
     * txt:3个
     * doc:5个
     * avi:2个
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {
        // 创建一个文件对象
        File f = new File ("D:\\aaa");
        // 调用方法
        int num = countFile (f, ".txt");
        System.out.println (".txt" + "文件有" + num + "个");
    }

    private static int countFile(File f, String suffix) {
        File[] files = f.listFiles ();
        int sum = 0;
        // 遍历文件列表
        for (File file : files) {
            // 判断是否是文件,且是否是指定的文件类型
            if (file.isFile () && file.getName ().endsWith (suffix)) {
                sum++;
            }
            // 判断是否是文件夹
            else if (file.isDirectory ()) {

                sum = sum + countFile (file, suffix);
            }

        }
        return sum;


    }


在这里插入图片描述

IO 流

介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

字节输入、输出流

每次操作 一个字节

字节输出流


  /**
         * 字节输出流,写一段文字到指定的文件中
         * 1.创建字节输出流对象
         * 2.写数据
         * 3.释放资源
         */
        FileOutputStream fos = new FileOutputStream (new File ("D:\\aaa\\a.txt"));
        // append为true,追加写入,默认false,覆盖写入
        FileOutputStream fos2 = new FileOutputStream ("D:\\aaa\\a.txt", true);
        
        // 写数据,写一个字节
        fos.write (65);
        byte[] data = {65, 66, 67};
        // 写数据,写一个字节数组
        fos.write (data);

        // 换行
        fos.write ("\r\n".getBytes ());

        fos.write ("一切很好".getBytes ());
        // 关闭流,释放资源
        fos.close ();

字节输入流

    public static void main(String[] args) throws IOException {
        /**
         * 字节输入流 循环读取数据
         */
        FileInputStream fis = new FileInputStream ("D:\\aaa\\a.txt");

        int b;
        /**
         * read读取一次,指针会移动一次
         */
        while ((b = fis.read ()) != -1) {
            System.out.println ((char) b);

        }
        fis.close ();
    }
 

文件拷贝

        /**
         * 文件拷贝
         */
        FileInputStream fis = new FileInputStream ("D:\\aaa\\a.txt");
        FileOutputStream fos = new FileOutputStream ("D:\\aaa\\b.txt");


        int b;

        while ((b = fis.read ()) != -1) {
            fos.write (b);

        }
        fos.close ();
        fis.close ();
        

    public static void main(String[] args) throws IOException {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            /**
             * 文件拷贝
             */
            fis = new FileInputStream ("D:\\aaa\\a.txt");
            fos = new FileOutputStream ("D:\\aaa\\b.txt");


            int len;
            byte[] data = new byte[1024];
            // read 读到data 中,返回的是读到的字节数
            while ((len = fis.read (data)) != -1) {
                // write 写入 data 中,从0 开始,写入 len 个字节
                fos.write (data, 0, len);

            }

        } catch (IOException e) {
            throw new RuntimeException (e);
        }
        /**
         * 关闭流
         * finally 一定会执行
         */
        finally {
            if (fis != null) {
                fis.close ();
            }
            if (fos != null) {
                fos.close ();
            }
        }
    }



字符集编码

在这里插入图片描述

        String s = "爱你哟";
        byte[] bytes = s.getBytes (); // 可以指定编码方式
        System.out.println (Arrays.toString (bytes));

字符输入流、输出流

在这里插入图片描述

FileReader

     FileReader fr = new FileReader ("D:\\aaa\\a.txt");

        int ch;

        while ((ch = fr.read ()) != -1) 
        {
            System.out.println (ch);
        }

        fr.close ();


    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader ("D:\\aaa\\a.txt");

        int len;


        char[] c = new char[1024];
        // 读取数据,并将数据存储在数组中
        // fr.read(c)返回的是读取到的有效字符个数
        // 将读取、解码、强转三步合并
        while ((len = fr.read (c)) != -1) {
            // 打印数组中的数据,从0索引到len索引
            System.out.println (new String (c, 0, len));
        }

        fr.close ();
    }

  FileReader fr = new FileReader ("D:\\aaa\\a.txt");


        FileWriter fw = new FileWriter ("D:\\aaa\\b.txt");
        int len;


        char[] c = new char[1024];
        // 读取文件,返回的是读取的字符个数
        while ((len = fr.read (c)) != -1) {
           fw.write (c,0,len);
        }

        fw.close ();
        fr.close ();
        FileReader fr = new FileReader ("D:\\aaa\\a.txt");

        fr.read (); // 将文件的数据放到缓冲区中
        FileWriter fw = new FileWriter ("D:\\aaa\\a.txt"); // append默认false,清空文件内容,true不清空

        int c;

        while ((c = fr.read ()) != -1) {
            // 只能读取 缓冲区中的数据
            // 文件中 剩余的数据无法读取
            System.out.println ((char) c);
        }

        fw.close ();
        fr.close ();

在这里插入图片描述

FileWriter

在这里插入图片描述

在这里插入图片描述



        // append默认false,清空文件内容,true不清空
        FileWriter fw = new FileWriter ("a.txt");

        // 写入数据
        char[] chars = {'a', 'b', 'c', '我'};
        fw.write (chars);


        // 在关闭之前,先刷新数据到文件中
        fw.close ();


      // append默认false,清空文件内容,true不清空
        FileWriter fw = new FileWriter ("a.txt");

        fw.write ("我的同学各个都很优秀");
        fw.write ("说话好听");
        fw.write ("学习刻苦");
        // 刷新,将内存中的数据写入到文件中
        fw.flush ();
        fw.write ("成绩优秀");
        fw.write ("是个好同学");

        // 在关闭之前,先刷新数据到文件中
        fw.close ();

在这里插入图片描述

练习

在这里插入图片描述

字节、字符缓冲流

字节 缓冲流

缓冲流 提高 读写效率

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


  /**
         * 缓冲流提高读写效率
         */
        BufferedInputStream bis = new BufferedInputStream (new FileInputStream ("D:\\aaa\\a.txt"));
        BufferedOutputStream bos = new BufferedOutputStream (new FileOutputStream ("D:\\aaa\\b.txt"));
        byte[] bytes = new byte[1024];
        int len = 0;
        // 往b.txt中写入a.txt中的内容
        while ((len = bis.read (bytes)) != -1) {
            bos.write (bytes, 0, len);
        }
        bis.close ();
        bos.close ();

内存运算速度 更快

在这里插入图片描述

字符 缓冲流

在这里插入图片描述
在这里插入图片描述

   /**
     * 缓冲流提高读写效率 readLine 
     *
     */
    BufferedReader br = new BufferedReader (new FileReader ("D:\\aaa\\a.txt"));


    // 一次读取一行
    String s1 = br.readLine ();
    System.out.println (s1);
    br.close ();


      /** 
         * 缓冲流提高读写效率  newLine 
         *
         */
        BufferedWriter bw = new BufferedWriter (new FileWriter ("D:\\aaa\\a.txt", true));
        bw.write ("你微笑的时候,我也微笑");
        // 换行
        bw.newLine ();
        bw.write ("你哭的时候,我也哭");
        bw.newLine ();
        bw.write ("你生气的时候,我也生气");
        bw.close ();

在这里插入图片描述

  public static void main(String[] args) throws IOException {


        /**
         * 从这个文件读取出师表
         */
        BufferedReader br = new BufferedReader (new FileReader ("D:\\aaa\\csb.txt"));
        // 一次读取一行

        String s;
        ArrayList<String> list = new ArrayList<> ();
        while ((s = br.readLine ()) != null) {
            // 将读取到的每一行添加到集合中
            list.add (s);

        }
        // 对集合进行排序
        Collections.sort (list, (o1, o2) -> {
            int i1 = Integer.parseInt (o1.split ("\\.")[0]);
            int i2 = Integer.parseInt (o2.split ("\\.")[0]);
            // 升序
            return i1 - i2;
        });


        BufferedWriter bw = new BufferedWriter (new FileWriter ("D:\\aaa\\dest.txt"));
        for (String data : list) {
            // 写入
            bw.write (data);
            // 换行
            bw.newLine ();
            // 刷新
            bw.flush ();
        }

        bw.close ();
        br.close ();

    }


序列化、反序列化流

序列化流

在这里插入图片描述
在这里插入图片描述


 /**
         * 将一个对象写到本地文件中
         */
        User user = new User ("张三", 18);

        ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("a.txt"));
        // 将对象写到本地文件中
        oos.writeObject (user);
        // 释放资源
        oos.close ();


反序列化 流

在这里插入图片描述


ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("a.txt"));
User o = (User) ois.readObject ();


System.out.println (o);
ois.close ();

在这里插入图片描述

使用细节



/**
 * Serializable接口
 * 表示可序列化的对象
 */
public class User implements Serializable {
    // 序列化版本号,固定好后,就不会再发生 序列化版本号不匹配的错误
    private static final long serialVersionUID = 1L;
    private String name;
    private int age;

    public User() {
    }

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


    /**
     * 获取
     *
     * @return name
     */
    public String getName() {
        return name;
    }

    /**
     * 设置
     *
     * @param name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 获取
     *
     * @return age
     */
    public int getAge() {
        return age;
    }

    /**
     * 设置
     *
     * @param age
     */
    public void setAge(int age) {
        this.age = age;
    }

    public String toString() {
        return "User{name = " + name + ", age = " + age + "}";
    }


}

在这里插入图片描述

在这里插入图片描述


  // transient 表示该属性不会被序列化
    private transient String address;

在这里插入图片描述

综合练习


       /**
         * 将多个自定义对象 序列化到一个文件中,对象个数不确定,如何操作?
         */

        // 创建数组
        List<User> list = new ArrayList<> ();
        ObjectOutputStream oos = new ObjectOutputStream (new FileOutputStream ("a.txt"));

        list.add (new User ("张三", 18));
        list.add (new User ("李四", 19));
        list.add (new User ("王五", 20));
        // 序列化
        oos.writeObject (list);
        oos.close ();


        ObjectInputStream ois = new ObjectInputStream (new FileInputStream ("a.txt"));
        // 读取对象
        List<User> list = (List<User>) ois.readObject ();

        // 遍历
        for (User user : list) {

            System.out.println (user);
        }
        ois.close ();

解压缩流

在这里插入图片描述
在这里插入图片描述

压缩


import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

public class ZIPCompress {
    public static void main(String[] args) {
        String sourceFile = "input.txt";  // 要压缩的文件
        String zipFile = "compressed.zip";  // 压缩后的 ZIP 文件

        try (FileOutputStream fos = new FileOutputStream(zipFile);
             ZipOutputStream zipOS = new ZipOutputStream(fos)) {

            FileInputStream fis = new FileInputStream(sourceFile);
            ZipEntry zipEntry = new ZipEntry(sourceFile);
            zipOS.putNextEntry(zipEntry);

            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                zipOS.write(buffer, 0, len);
            }

            zipOS.closeEntry();
            fis.close();

            System.out.println("文件压缩完成!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ZipOutputStream 用于将文件压缩为 ZIP 格式。我们通过 putNextEntry() 创建新的 ZIP 条目,并将每个文件的内容写入 ZIP 文件中。
closeEntry() 用于关闭当前 ZIP 条目,表明该文件的压缩已完成。

解压

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

public class ZIPDecompress {
    public static void main(String[] args) {
        String zipFile = "compressed.zip";  // 压缩文件
        String outputDir = "output/";  // 解压后的输出目录

        try (FileInputStream fis = new FileInputStream(zipFile);
             ZipInputStream zis = new ZipInputStream(fis)) {

            ZipEntry zipEntry = zis.getNextEntry();
            while (zipEntry != null) {
                String outputFile = outputDir + zipEntry.getName();
                FileOutputStream fos = new FileOutputStream(outputFile);

                byte[] buffer = new byte[1024];
                int len;
                while ((len = zis.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                }

                fos.close();
                zis.closeEntry();
                zipEntry = zis.getNextEntry();
            }

            System.out.println("文件解压完成!");

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ZipInputStream 允许我们解压 ZIP 文件中的多个条目。我们通过getNextEntry()获取 ZIP 文件中的每个条目,并将解压后的内容输出到指定目录

解压缩流与压缩流的应用场景:

  • 文件压缩:当需要减少文件大小以便传输或存储时,可以使用压缩流对文件进行压缩,常用于日志文件压缩、备份等场景。
  • 网络传输:在网络传输中,压缩流能有效减少数据体积,缩短传输时间,特别适用于需要大量数据传输的应用。
  • 数据备份:压缩流可以用来创建备份文件,特别是将多个文件或目录压缩成一个 ZIP 文件,方便存储和分发。

常用 IO工具包

Commons-io


File src = new File ("D:\\aaa\\a.txt");
File dest = new File("D:\\aaa\\b.txt");

FileUtils.copyFile(src,dest);

Hutool 工具包

在这里插入图片描述

在这里插入图片描述


File file = FileUtil.file ("D:\\aaa\\c.txt");
file.createNewFile ();
ArrayList<String> list = new ArrayList<> ();

Collections.addAll (list,"我们不一样","你很牛啊","我不服");
FileUtil.writeLines (list,"D:\\aaa\\a.txt","utf-8",false);

在这里插入图片描述


ArrayList<String> list = new ArrayList<> ();

ArrayList<String> strings = FileUtil.readLines ("D:\\aaa\\a.txt", "utf-8", list);
for (String s : strings) {
    System.out.print (s+" ");
}

在这里插入图片描述

多线程&JUC

线程

在这里插入图片描述
在这里插入图片描述

        new Thread (() -> {


            int count=1;
            for (int i = 0; i < 100; i++) {
                String name = Thread.currentThread ().getName ();
                System.out.println (name+" hello world " +(count++));
            }

        }).start ();
        new Thread (() -> {


            int count=1;
            for (int i = 0; i < 100; i++) {
                String name = Thread.currentThread ().getName ();
                System.out.println (name+" hello world " +(count++));
            }

        }).start ();

在这里插入图片描述

Thread 类常见成员方法

在这里插入图片描述

线程的生命周期、安全问题


public class Ticket
{
    public int getNum() {
        return num;
    }

    public void setNum(int num) {
        this.num = num;
    }


    public Ticket(int num) {
        this.num = num;
    }

    private  int num;

    public void  sale(String window) {
       while (num > 0) {
           try {
               Thread.sleep (100);
           } catch (InterruptedException e) {
               throw new RuntimeException (e);
           }
           System.out.println (window + "卖出了第" + num-- + "张票");
       }
    }
}



        /**
         * 某电影院共有100张票,现有3个窗口卖票
         */

        Ticket ticket = new Ticket (100);

        new Thread (
                () -> {
                    for (int i = 0; i < 1000; i++) {
                        ticket.sale ("窗口1");
                    }
                }
        ).start ();
        new Thread (
                () -> {
                    for (int i = 0; i < 1000; i++) {
                        ticket.sale ("窗口2");
                    }
                }
        ).start ();
        new Thread (
                () -> {
                    for (int i = 0; i < 1000; i++) {
                        ticket.sale ("窗口3");
                    }
                }
        ).start ();

超卖, 超过了库存

在这里插入图片描述

在这里插入图片描述

解决超卖


   public void sale(String window) {

        /**
         * 出现线程安全问题
         * 解决方式:
         * 1、同步代码块
         * 2、同步方法
         * 3、lock锁
         */
        synchronized (this) {
            if (num > 0) {
                try {
                    Thread.sleep (100);
                } catch (InterruptedException e) {
                    throw new RuntimeException (e);
                }
                System.out.println (window + "卖出了第" + num-- + "张票");
            }
        }


    }

在这里插入图片描述

同步代码块

在这里插入图片描述


       /**
         * 出现线程安全问题
         * 解决方式:
         * 1、同步代码块
         * 2、同步方法
         * 3、lock锁
         */
        synchronized (this) {
            if (num > 0) {
                try {
                    Thread.sleep (100);
                } catch (InterruptedException e) {
                    throw new RuntimeException (e);
                }
                System.out.println (window + "卖出了第" + num-- + "张票");
            }
        }


 public void sale(String window) {


        ReentrantLock lock = new ReentrantLock ();
        lock.lock ();
        try {
            if (num > 0) {
                try {
                    Thread.sleep (100);
                } catch (InterruptedException e) {
                    throw new RuntimeException (e);
                }
                System.out.println (window + "卖出了第" + num-- + "张票");
            }
        } finally {
            lock.unlock ();
        }


    }

在这里插入图片描述

为什么 还是出现了超卖?
每次调用该方法都会创建一个锁~每次锁对象不同
解决:将锁 置为 成员变量

// 每次 锁对象就这一个~
private ReentrantLock lock = new ReentrantLock ();

    public void sale(String window) {
        lock.lock ();
        try {
            if (num > 0) {
                try {
                    Thread.sleep (100);
                } catch (InterruptedException e) {
                    throw new RuntimeException (e);
                }
                System.out.println (window + "卖出了第" + num-- + "张票");
            }
        } finally {
            lock.unlock ();
        }


    }

在这里插入图片描述

等待唤醒机制 wait / notify

在这里插入图片描述

在这里插入图片描述

线程 操作 资源类

在这里插入图片描述

桌子:


public class Desk {
    // 总个数 10
    public static int count = 10;

    // 食物标志《0 没有食物 1有食物》
    public static int foodFlag = 0;

    // 同步锁
    public static Object lock = new Object ();

}

厨师:


public class Cook extends Thread {
    /**
     * 1、循环
     * 2、同步代码块
     * 3、判断数据是否到了末尾(到了末尾,就不再循环)
     * 4、判断数据是否到了末尾(没有到末尾,执行代码核心逻辑)
     */
    @Override
    public void run() {

        //  不停的循环
        while (true) {
            // 每次只允许一个线程进入
            synchronized (Desk.lock) {
                Desk.foodFlag = 1;// 有食物
                // 当食物数量大于 10的时候,就不再生产

                if (Desk.count >= 10) {
                    try {
                        Desk.lock.wait (); //  食物数量大于 10的时候,就不再生产
                    } catch (InterruptedException e) {
                        throw new RuntimeException (e);
                    }
                } else {
                    System.out.println (getName () + "正在生产第" + (++Desk.count) + "个汉堡");
                }


            }
        }
    }

}


吃饭者:


public class Foodies extends Thread {
    /**
     * 1、循环
     * 2、同步代码块
     * 3、判断数据是否到了末尾(到了末尾,就不再循环)
     * 4、判断数据是否到了末尾(没有到末尾,执行代码核心逻辑)
     */
    @Override
    public void run() {

        //  不停的循环
        while (true) {
            // 每次只允许一个线程进入
            synchronized (Desk.lock) {
                if (Desk.count <= 0) {
                    Desk.foodFlag = 0;// 没有食物
                    Desk.lock.notifyAll (); // 唤醒所有线程
                } else {
                    System.out.println (getName () + "正在吃第" + (Desk.count--) + "个汉堡");
                }
            }
        }
    }
}



综合练习

抢红包


public class GetRed extends Thread {


    // static 属于类
    private static BigDecimal money = new BigDecimal ("100");
    private static int count = 3;
    private static final BigDecimal MIN = new BigDecimal ("0.01");

    private String name;

    public GetRed(String name) {
        super (name);
    }

    /**
     * 微信中的抢红包
     * 100 块,分成三个包,现有 3人去抢
     * 红包是共享数据
     * 最小中奖金额 0.01
     */

    @Override
    public void run() {

        synchronized (GetRed.class) {
            if (count == 0) {
                // 抢完了
                System.out.println (getName () + "没抢到红包");
            } else {

                BigDecimal prize;
                // 最后一个红包
                if (count == 1) {
                    prize = money;
                } else {
                    // 不是最后一个红包
                    // 因为每次抽奖金额最低是 0.01 ,所以每次抽奖的最大值是剩余红包金额 - 0.01 * 剩余红包个数
                    prize = BigDecimal.valueOf (Math.random () * money.floatValue () - (count - 1) * MIN.floatValue ());

                }
                prize = prize.setScale (2, RoundingMode.HALF_UP);
                money = money.subtract (prize);
                count--;
                System.out.println (getName () + "抢到红包" + prize + "元");

            }

        }

    }
}


    public static void main(String[] args) throws IOException, ClassNotFoundException {

        new GetRed ("张三").start ();
        new GetRed ("李四").start ();
        new GetRed ("王五").start ();


    }


在这里插入图片描述

线程池

在这里插入图片描述
在这里插入图片描述

业务开发使用 :自定义线程池,方便使用

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


// 最大线程数
System.out.println (Runtime.getRuntime ().availableProcessors ());

在这里插入图片描述


  ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor (
                3, // 核心线程数
                6, // 最大线程数
                10, // 空闲线程存活时间
                TimeUnit.SECONDS, // 时间单位
                new ArrayBlockingQueue<> (100), // 阻塞队列
                new ThreadPoolExecutor.AbortPolicy () // 拒绝策略
        );

volatile

保证多线程变量的 可见性