Java基础复习(三)

该复习笔记是基于传智播客的Java基础视频-深入简出精华版,链接: https://pan.baidu.com/s/1bp7NuOJ,建议刚刚入门的小白不要看,因为涉及太多的细节了,看多了反而让你容易放弃Java之路,刚刚入门的小白推荐下面这一套视频-链接:https://pan.baidu.com/s/1pLuAj5x

博主声明一下:我不是传智播客的什么托,只是一个菜鸟,现在在补着Java基础,搞了一套传智播客的Java视频以及Android视频,所以笔记可能会常出现这些字眼,请言语讽刺我是托的麻烦你闭嘴哈

异常

JVM默认是如何处理异常的

  • A:JVM默认是如何处理异常的

    • main函数收到这个问题时,有两种处理方式:
    • a:自己将该问题处理,然后继续运行
    • b:自己没有针对的处理方式,只有交给调用main的jvm来处理
    • jvm有一个默认的异常处理机制,就将该异常进行处理.
    • 并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上,同时将程序停止运行
  • B:异常处理的两种方式

    • a:try…catch…finally
      try:用来检测异常的
      catch:用来捕获异常的
      finally:释放资源
      当通过trycatch将问题处理了,程序会继续执行

      • 安卓,客户端开发,如何处理异常?try{}catch(Exception e){}
      • ee,服务端开发,一般都是底层开发,从底层向上抛
      • try后面如果跟多个catch,那么小的异常放前面,大的异常放后面,根据多态的原理,如果大的放前面,就会将所有的子类对象接收,后面的catch就没有意义了
    • b:throws

特别强调:JDK7处理多个异常

        int a = 10;
        int b = 0;
        int[] arr = {11,22,33,44,55};

        //JDK7如何处理多个异常
        try {
            System.out.println(a / b);
            System.out.println(arr[10]);
        } catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
            System.out.println("出错了");
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println("我都可以接收到你的错误");
        }

编译期异常和运行期异常的区别

  • A:编译期异常和运行期异常的区别

    • Java中的异常被分为两大类:编译时异常和运行时异常。
    • 所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常

    • 编译时异常

      • Java程序必须显示处理,否则程序就会发生错误,无法通过编译
    • 运行时异常
      • 无需显示处理,也可以和编译时异常一样处理

Throwable的几个常见方法

  • A:Throwable的几个常见方法
    • a:getMessage()
      • 获取异常信息,返回字符串。
    • b:toString()
      • 获取异常类名和异常信息,返回字符串。
    • c:printStackTrace()
      • 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
      • jvm默认就用这种方式处理异常

throws的方式处理异常

  • A:throws的方式处理异常
    • 定义功能方法时,需要把出现的问题暴露出来让调用者去处理。
    • 那么就通过throws在方法上标识。
  • B:throw的概述
    • 在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
  • C:throws和throw的区别
    • a:throws
      • 用在方法声明后面,跟的是异常类名
      • 可以跟多个异常类名,用逗号隔开
      • 表示抛出异常,由该方法的调用者来处理
    • b:throw
      • 用在方法体内,跟的是异常对象名
      • 只能抛出一个异常对象名
      • 表示抛出异常,由方法体内的语句处理

finally关键字的特点及作用

  • A:finally的特点
    • 被finally控制的语句体一定会执行
    • 特殊情况:在执行到finally之前jvm退出了(比如退出jvm虚拟机System.exit(0))
    • B:finally的作用
    • 用于释放资源,在IO流操作和数据库操作中会见到
finally关键字的面试题
  • A:面试题1

    • final,finally和finalize的区别
      final可以修饰类(不能被继承),修饰方法(不能被重写),修饰变量(只能赋值一次)
      finally是try语句中的一个语句体,不能单独使用,用来释放资源
      finalize是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
  • B:面试题2

    • 如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。
public class Test1 {

    public static void main(String[] args) {
        Demo d = new Demo();
        System.out.println(d.method());//30,最新解释:return语
        //句在返回时候不是直接返回变量的值,而是复制一份,然后返回.在finally
        //块中改变return的值对返回值没有任何影响,而对引用数据类型的数据会有影响
    }

}
//return语句相当于是方法的最后一口气,那么在他将死之前会看一看有没有finally帮其完成遗愿,
//如果有就将finally执行后在彻底返回
class Demo {
    public int method() {
        int x = 10;
        try {
            x = 20;
            System.out.println(1 / 0);
            return x;
        } catch (Exception e) {
            x = 30;// 出现异常到这里
            return x;// 这个x已经被装入返回的箱子了,接着在执行return的时候就去执行finally方法,
            // 此时不是装入retrun语句箱子里面的x变为40,但装在x语句中的return的值依然为30,
            // finally执行完毕之后,return就会完全执行,退出方法
        } finally {
            x = 40;
            System.out.println("finally的x:" + x);//40
            // 千万不要在finally里面写返回语句,因为finally的作用是为了释放资源,是肯定会执行的
            // return x; // 如果在这里面写返回语句,那么try和catch的结果都会被改变,所以这么写就是犯罪
        }
    }
}

异常的注意事项及如何使用异常处理

  • A:异常注意事项
    • a:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
    • b:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
    • c:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
  • B:如何使用异常处理

    • 原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
    • 区别:

      • 后续程序需要继续运行就try
      • 后续程序不需要继续运行就throws
    • 如果JDK没有提供对应的异常,需要自定义异常。

File类的概述和构造方法

  • A:File类的概述
    • File更应该叫做一个路径
      • 文件路径或者文件夹路径
      • 路径分为绝对路径和相对路径
      • 绝对路径是一个固定的路径,从盘符开始
      • 相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下
    • 文件和目录路径名的抽象表示形式
  • B:构造方法
    1. File(String pathname):根据一个路径得到File对象
    2. File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
    3. File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
        //第2种构造方法
        String parent = "F:\\双元课堂\\day19\\video";
        String child = "001_今日内容.avi";
        File file = new File(parent,child);
        System.out.println(file.exists());
        //第3种构造方法
        File parent = new File("F:\\双元课堂\\day19\\video");
        String child = "001_今日内容.avi";
        File file = new File(parent, child);
        System.out.println(file.exists());
        System.out.println(parent.exists());

File类的功能

  • A:创建功能

    • public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
    • public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
    • public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来(创建多级目录)
    • 注意事项:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
  • B:重命名和删除功能

    • public boolean renameTo(File dest):把文件重命名为指定的文件路径
    • public boolean delete():删除文件或者文件夹

      • a:重命名注意事项
      • 如果路径名相同,就是改名。
      • 如果路径名不同,就是改名并剪切。
      • b:删除注意事项:
      • Java中的删除不走回收站。
      • 要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
  • C:获取功能

    • public String getAbsolutePath():获取绝对路径
    • public String getPath():获取路径(构造方法传什么路径就获取什么路径)
    • public String getName():获取名称(获取文件或者文件夹的名字)
    • public long length():获取长度。字节数
    • public long lastModified():获取最后一次的修改时间,毫秒值(一般结合SimpleDateFormat跟Date使用)
    • public String[] list():获取指定目录下的所有文件或者文件夹的名称数组(仅为了获取文件名)
    • public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组(获取文件对象进而可获得文件的绝对路径)
  • D:判断功能

    • public boolean isDirectory():判断是否是目录
    • public boolean isFile():判断是否是文件
    • public boolean exists():判断是否存在
    • public boolean canRead():判断是否可读
    • public boolean canWrite():判断是否可写
    • public boolean isHidden():判断是否隐藏
        File file = new File("zzz");
        //windows系统认为所有的文件都是可读的
        file.setReadable(false);
        System.out.println(file.canRead()); //true  
        //windows系统可以设置为不可写
        file.setWritable(true);
        System.out.println(file.canWrite()); //true         

        File file2 = new File("aaa.txt");//在系统中设置其为隐藏文件
        //判断是否是隐藏文件
        System.out.println(file2.isHidden());//true         
        System.out.println(file.isHidden());//false
文件名称过滤器的概述及使用
  • A:文件名称过滤器的概述
    • public String[] list(FilenameFilter filter)
    • public File[] listFiles(FileFilter filter)
  • B:文件名称过滤器的使用
    • 需求:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称

IO流概述及其分类

  • 1.概念
    • IO流用来处理设备之间的数据传输
    • Java对数据的操作是通过流的方式
    • Java用于操作流的类都在IO包中
    • 流按流向分为两种:输入流,输出流。
    • 流按操作类型分为两种:
      • 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
      • 字符流 : 字符流只能操作纯字符数据,比较方便。
  • 2.IO流常用父类
    • 字节流的抽象父类:
      • InputStream
      • OutputStream(创建字节输出流对象,如果没有就自动创建一个)
    • 字符流的抽象父类:
      • Reader
      • Writer
  • 3.IO程序书写
    • 使用前,导入IO包中的类
    • 使用时,进行IO异常处理
    • 使用后,释放资源

思考题: read()方法读取的是一个字节,为什么返回是int,而不是byt

    因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
    那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
    24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
    /** 
     * read()方法读取的是一个字节,为什么返回是int,而不是byte
     * 
     * 文件存储的二进制形式:
     * 00010100 00100100 01000001 11111111 0000000
     * 
     * 假设是byte类型(占1个字节)读取,当到了11111111的时候是byte类型的-1,读取停止
     * 10000001    byte类型-1的原码
     * 11111110    -1的反码
     * 11111111    -1的补码
     * 
     * 假设是int类型读取,那么11111111就自动变成下面这个(int占4个字节)
     * 00000000 00000000 00000000 11111111 
     *PS:上面文件存储的二进制都会自动转为int类型(以0补够)
     * 
     * 放心,write会自动把前三补的0自动砍掉(到时我们写回去硬盘的时候)
     * fos.write(97)虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前三个8位
     */

定义小数组的标准格式

  • write(byte[] b)
  • write(byte[] b, int off, int len)写出有效的字节个数
    Java基础复习(三)_第1张图片
        FileInputStream fis = new FileInputStream("致青春.mp3");
        FileOutputStream fos = new FileOutputStream("copy.mp3");

        byte[] arr = new byte[1024 * 8];
        int len;
        // 如果忘记加arr,返回的就不是读取的字节个数,而是字节的码表值
        // fis.read(arr)返回的是读取的字节个数
        // fis.read()返回的是字节的码表值
        while ((len = fis.read(arr)) != -1) {
            fos.write(arr, 0, len);////写出字节数组有效个数
        }

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

BufferedInputStream和BufferOutputStream拷贝

  • A:缓冲思想
    • 字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,
    • 这是加入了数组这样的缓冲区效果,java本身在设计的时候,
    • 也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流
  • B.BufferedInputStream
    • BufferedInputStream内置了一个缓冲区(数组)
    • 从BufferedInputStream中读取一个字节时
    • BufferedInputStream会一次性从文件中读取8192个, 存在缓冲区中, 返回给程序一个
    • 程序再次读取时, 就不用找文件了, 直接从缓冲区中获取
    • 直到缓冲区中所有的都被使用过, 才重新从文件中读取8192个
  • C.BufferedOutputStream
    • BufferedOutputStream也内置了一个缓冲区(数组)
    • 程序向流中写出字节时, 不会直接写到文件, 先写到缓冲区中
    • 直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
      Java基础复习(三)_第2张图片
        // 创建输入流对象,关联致青春.mp3
        FileInputStream fis = new FileInputStream("致青春.mp3");
        // 创建输出流对象,关联copy.mp3
        FileOutputStream fos = new FileOutputStream("copy.mp3");
        // 创建缓冲区对象,对输入流进行包装让其变得更加强大
        BufferedInputStream bis = new BufferedInputStream(fis);
        BufferedOutputStream bos = new BufferedOutputStream(fos);

        int b;
        //bis以及bos类内置byte buf[]=new byte[8192];
        while ((b = bis.read()) != -1) {
            bos.write(b);
        }

        bis.close();//关闭流释放资源
        bos.close();//关闭流释放资源

思考题:小数组的读写和带Buffered的读取哪个更快?
1. 定义小数组如果是8192个字节大小和Buffered比较的话
2. 定义小数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组

OutputStream类中的flush和close方法的区别

  • flush()方法
    • 用来刷新缓冲区的,刷新后可以再次写出
  • close()方法
    • ###20.12_IO流(OutputStream
      中的flush和close方法的区别)
  • flush()方法
    • 用来刷新缓冲区的,刷新后可以再次写出
  • close()方法
    • 用来关闭流释放资源的的,如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出

io流字节流读写中文

  • 字节流读取中文的问题
    • 字节流在读中文的时候有可能会读到半个中文,造成乱码
  • 字节流写出中文的问题
    • 字节流直接操作的字节,所以写出中文必须将字符串转换成字节数组
    • 写出回车换行 write(“\r\n”.getBytes());

流的标准处理异常代码1.6版本及其以前

  • try finally嵌套
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("xxx.txt");
            fos = new FileOutputStream("yyy.txt");

            int b;
            while((b = fis.read()) != -1) {
                fos.write(b);
            }
        }finally {
        //try fianlly的嵌套目的是能关一个尽量关一个
            try{
                if(fis != null)
                    fis.close();
            }finally {      
                if(fos != null)
                    fos.close();
            }
        }
    }

流的标准处理异常代码1.7版本

  • try close
        try(
            FileInputStream fis = new FileInputStream("xxx.txt");
            FileOutputStream fos = new FileOutputStream("yyy.txt");
        ){
            int b;
            while((b = fis.read()) != -1) {
                fos.write(b);
            }
            //当执行完毕{}里面的代码,fis跟fos自动关闭(JDK1.7新特性之一)
            //InputStream跟OutputStream都继承AutoCloseable接口
            //写在()里面的代码都必须具备自动关闭功能,否则编译不可以通过
        }

原理:在try()中创建的流对象必须实现了AutoCloseable这个接口,如果实现了,在try后面的{}(读写代码)执行后就会自动调用,流对象的close方法将流关掉

面试题:

  1. 给图片加密
    /**
     * @param args
     * @throws IOException 
     * 将写出的字节异或上一个数,这个数就是密钥,解密的时候再次异或就可以了
     */
    public static void main(String[] args) throws IOException {
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream("copy.jpg"));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy2.jpg"));

        int b;
        while((b = bis.read()) != -1) {
            bos.write(b ^ 123);//^一个数字偶数次变回自己
        }

        bis.close();
        bos.close();
    }

2.在控制台录入文件的路径,将文件拷贝到当前项目下

    /**
     * 在控制台录入文件的路径,将文件拷贝到当前项目下
     * 
     * 分析:
     * 
     * 1,定义方法对键盘录入的路径进行判断,如果是文件就返回
     * 2,在主方法中接收该文件
     * 3,读和写该文件
     * @throws IOException 
     */
    public static void main(String[] args) throws IOException {


        File file = getFile();  //获取文件
        //File file1 = new File("F:\\xin.mp3");这里的文件路径必须\\((否则编译不通过)),第一个\是转义的意思
        //String path="F:\\xin.mp3";//这里必须是\\(否则编译不通过),第一个\是转义的意思
        //File file2 = new File(path);
        BufferedInputStream  bis = new BufferedInputStream(new FileInputStream(file));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file.getName()));

        int b;
        while((b = bis.read()) != -1) {
            bos.write(b);
        }

        bis.close();
        bos.close();
    }

    /*
     * 定义一个方法获取键盘录入的文件路径,并封装成File对象返回
     * 1,返回值类型File
     * 2,参数列表无
     */
    public static File getFile() {
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);                
        System.out.println("请输入一个文件的路径:");
        while(true) {
            //接收键盘录入的路径,这个nextLine()对路径有优化的作用
            //当你写\的时候,它会自动帮你转为\\,当你写\\的时候它就不处理了
            String line = sc.nextLine();
            //封装成File对象,并对其进行判断
            File file = new File(line);                     
            if(!file.exists()) {
                System.out.println("您录入的文件路径不存在,请重新录入:");
            }else if(file.isDirectory()) {
                System.out.println("您录入的是文件夹路径,请重新录入:");
            }else {
                return file;
            }
        }
    }

字符流FileReader和FileWriter

  • 1.字符流是什么

    • 字符流是可以直接读写字符的IO流
    • 字符流读取字符, 就要先读取到字节数据, 然后转为字符. 如果要写出字符, 需要把字符转为字节再写出. (计算机存取的是字节数据)
  • 2.FileWriter继承的Writer类中有一个2k的小缓冲区,如果不关流,就会将内容写到缓冲区里,关流会将缓冲区内容刷新,再关闭

什么情况下使用字符流
  • 字符流也可以拷贝文本文件, 但不推荐使用. 因为读取时会把字节转为字符, 写出时还要把字符转回字节.
  • 程序需要读取一段文本, 或者需要写出一段文本的时候可以使用字符流(只读或者只写的时候)
    • 读取的时候是按照字符的大小读取的,不会出现半个中文
    • 写出的时候可以直接将字符串写出,不用转换为字节数组
      Java基础复习(三)_第3张图片
字符流是否可以拷贝非纯文本的文件
  • 不可以拷贝非纯文本的文件
    • 因为在读的时候会将字节转换为字符,在转换过程中,可能找不到对应的字符,就会用?代替,写出的时候会将字符转换成字节写出去
    • 如果是?,直接写出,这样写出之后的文件就乱了,看不了了

带缓冲的字符流

  • BufferedReader的read()方法读取字符时会一次读取若干字符到缓冲区, 然后逐个返回给程序, 降低读取文件的次数, 提高效率
  • BufferedWriter的write()方法写出字符时会先写到缓冲区, 缓冲区写满时才会写到文件, 降低写文件的次数, 提高效率
带缓冲的字符流中的readLine()和newLine()方法
  • BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
  • BufferedWriter的newLine()可以输出一个跨平台的换行符号”\r\n”
    • newLine()与\r\n的区别
    • newLine()是跨平台的方法
    • \r\n只支持的是windows系统(Mac一个\r就可以了,lunix系统一个\n就可以了)
        BufferedReader br = new BufferedReader(new FileReader("zzz.txt"));
        BufferedWriter bw = new BufferedWriter(new FileWriter("aaa.txt"));

        String line;
        while((line = br.readLine()) != null) {
            bw.write(line);
            //bw.newLine();//写出回车换行符,跨平台,无论lunix还是Windows系统
            //bw.write("\r\n");//Windows系统可以识别,但lunix系统不识别
        }

        br.close();//流对象尽量晚开早关
        bw.close();

LineNumberReader

  • LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号
    • 调用getLineNumber()方法可以获取当前行号
    • 调用setLineNumber()方法可以设置当前行号
        LineNumberReader lnr = new LineNumberReader(new FileReader("zzz.txt"));

        String line;
        lnr.setLineNumber(100);//设置从100行开始
        while((line = lnr.readLine()) != null) {
            //lnr.readLine()使用一次,lineNumber变回自从加1,所以显示的时候是从101行开始的
            System.out.println(lnr.getLineNumber() + ":" + line);
        }

        lnr.close();
    }

装饰设计模式

装饰设计模式个人小理解:
* 当Student刚刚毕业走出社会的时候,只会Javase以及Javaweb,工资不高,接着黑马学校可以把你的技能进行升级,让你拥有数据库,大数据等更多的技能,工资便会更高
* HeiMaStudent为什么不直接继承Student重写方法呢?这样耦合性太高了,假如Student改一改,接着HeiMaStudent也要跟着改变

public class Demo6_Wrap {

    /**
     * @param args
     * 装饰设计模式的好处是:
     * 耦合性不强,被装饰的类的变化与装饰类的变化无关
     */
    public static void main(String[] args) {
        HeiMaStudent hms = new HeiMaStudent(new Student());
        hms.code();
    }

}

interface Coder {
    public void code();
}

class Student implements Coder {

    @Override
    public void code() {
        System.out.println("javase");
        System.out.println("javaweb");
    }

}

class HeiMaStudent implements Coder {
    //1,获取被装饰类的引用
    private Student s;                      //获取学生引用

    //2,在构造方法中传入被装饰类的对象
    public HeiMaStudent(Student s) {
        this.s = s;
    }

    //3,对原有的功能进行升级
    @Override
    public void code() {
        s.code();
        System.out.println("ssh");
        System.out.println("数据库");
        System.out.println("大数据");
        System.out.println("...");
    }
}

使用指定的码表读写字符

  • FileReader是使用默认码表读取文件, 如果需要使用指定码表读取, 那么可以使用InputStreamReader(字节流,编码表)
  • FileWriter是使用默认码表写出文件, 如果需要使用指定码表写出, 那么可以使用OutputStreamWriter(字节流,编码表)

其中:
FileInputStream跟FileOutputStream无论是构造方法还是方法里面都没有指定码表的办法,但FileOutputStream可以根据方法write的时候让字符转为其他码表,fos.write(“str”.getBytes(“utf-8”));

  • 嫌速度不够快,还可以借用BufferedReader或者BufferedWriter进行加装读写
        InputStreamReader isr = new InputStreamReader(
                new FileInputStream("utf-8.txt"), "uTf-8"); //指定码表读字符
        OutputStreamWriter osw = new OutputStreamWriter(
                new FileOutputStream("gbk.txt"), "gbk");    //指定码表写字符

        int c;
        while((c = isr.read()) != -1) {
            osw.write(c);
        }

        isr.close();
        osw.close();

Java基础复习(三)_第4张图片

面试题:
当我们下载一个试用版软件,没有购买正版的时候,每执行一次就会提醒我们还有多少次使用机会用学过的IO流知识,模拟试用版软件,试用10次机会,执行一次就提示一次您还有几次机会,如果次数到了提示请购买正版

        //1,创建带缓冲的输入流对象,因为要使用readLine方法,可以保证数据的原样性
        BufferedReader br = new BufferedReader(new FileReader("config.txt"));//config.txt中只有10数字
        //2,将读到的字符串转换为int数
        String line = br.readLine();
        int times = Integer.parseInt(line);                 //将数字字符串转换为数字
        //3,对int数进行判断,如果大于0,就将其--写回去,如果不大于0,就提示请购买正版
        if(times > 0) {
            //4,在if判断中要将--的结果打印,并将结果通过输出流写到文件上
            System.out.println("您还有" + times-- + "次机会");
            FileWriter fw = new FileWriter("config.txt");
            fw.write(times + "");
            fw.close();
            /*FileOutputStream fos = new FileOutputStream("config.txt");
            fos.write((times + "").getBytes());
            fos.close();*/
        }else {
            System.out.println("您的试用次数已到,请购买正版");
        }
        //关闭流
        br.close();

上题不可以使用FileInputStream(字节流)或者FileReader(字符流)读config.txt文件的时候,输出的结果是49以及48(根据ASCII码表)

        FileReader fr = new FileReader("config.txt");
        //FileInputStream fis = new FileInputStream("config.txt");
        int c;
        //while ((c=fis.read())!=-1) {
        while ((c=fr.read())!=-1) {
            System.out.print(c+"  ");//输出49 48
        }
        fr.close();
        //fis.close();

递归(自己调用自己)

  • 递归的弊端:不能调用次数过多,容易导致栈内存溢出
  • 递归的好处:不用知道循环次数
  • 构造方法不能使用递归调用
  • 递归调用不一定需要有返回值

使用递归求5的阶乘

public class Demo8_Digui {

    /**
     * @param args
     * 递归:方法自己调用自己
     * 5!
     * 5 * 4 * 3 * 2 * 1
     * 
     * 5 * fun(4)(代表4!)
     *      4 * fun(3)(代表3!)
     *              3 * fun(2)(代表2!) 
     *                      2 * fun(1)(代表1!)
     */
    public static void main(String[] args) {

        System.out.println(fun(5));//120
    }

    public static int fun(int num) {
        if(num == 1) {
            return 1;
        }else {
            return num * fun(num - 1);
        }
    }
}

面试题:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名

public class Test5 {

    /**
     * 需求:从键盘输入接收一个文件夹路径,打印出该文件夹下所有的.java文件名
     * 
     * 分析:
     * 从键盘接收一个文件夹路径
     * 1,如果录入的是不存在,给与提示
     * 2,如果录入的是文件路径,给与提示
     * 3,如果是文件夹路径,直接返回
     * 
     * 打印出该文件夹下所有的.java文件名
     * 1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
     * 2,遍历数组,对每一个文件或文件夹做判断
     * 3,如果是文件,并且后缀是.java的,就打印
     * 4,如果是文件夹,就递归调用
     */
    public static void main(String[] args) {
        File dir = getDir();
        printJavaFile(dir);
    }

    /*
     * 获取键盘录入的文件夹路径
     * 1,返回值类型File
     * 2,不需要有参数
     */
    public static File getDir() {
        Scanner sc = new Scanner(System.in);                //创建键盘录入对象
        System.out.println("请输入一个文件夹路径");
        while(true) {
            String line = sc.nextLine();                    //将键盘录入的文件夹路径存储
            File dir = new File(line);                      //封装成File对象
            if(!dir.exists()) {
                System.out.println("您录入的文件夹路径不存在,请重新录入");
            }else if(dir.isFile()) {
                System.out.println("您录入的是文件路径,请重新录入文件夹路径");
            }else {
                return dir;
            }
        }
    }
    /*
     * 获取文件夹路径下的所.java文件
     * 1,返回值类型 void
     * 2,参数列表File dir
     */
    public static void printJavaFile(File dir) {
        //1,获取到该文件夹路径下的所有的文件和文件夹,存储在File数组中
        File[] subFiles = dir.listFiles();
        //2,遍历数组,对每一个文件或文件夹做判断
        for (File subFile : subFiles) {
            //3,如果是文件,并且后缀是.java的,就打印
            if(subFile.isFile() && subFile.getName().endsWith(".java")) {
                System.out.println(subFile);
            //4,如果是文件夹,就递归调用
            }else if (subFile.isDirectory()){
                printJavaFile(subFile);
            }
        }
    }
}

序列流(了解)

  • 1.什么是序列流
    • 序列流可以把多个字节输入流整合成一个, 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.
      Java基础复习(三)_第5张图片
  • 2.使用方式
    • 整合多个输入流: SequenceInputStream(Enumeration
        FileInputStream fis1 = new FileInputStream("a.txt");
        FileInputStream fis2 = new FileInputStream("b.txt");
        FileInputStream fis3 = new FileInputStream("c.txt");

        //将流对象存储进来
        Vector v = new Vector<>(); 
        //创建集合对象
        v.add(fis1);                                                
        v.add(fis2);
        v.add(fis3);

        Enumeration en = v.elements();
        //将枚举中的输入流整合成一个
        SequenceInputStream sis = new SequenceInputStream(en);      
        FileOutputStream fos = new FileOutputStream("d.txt");

        int b;
        while((b = sis.read()) != -1) {
            fos.write(b);
        }

        sis.close();//sis在关闭的时候,会将构造方法中传入的流对象也都关闭
        fos.close();

内存输出流(掌握)

  • 1.什么是内存输出流
    • 该输出流可以向内存中写数据, 把内存当作一个缓冲区, 写出之后可以一次性获取出所有数据
  • 2 FileInputStream读取中文的时候出现了乱码的解决方案
    • 1,字符流读取
    • 2,ByteArrayOutputStream
  • 3.使用方式
    • 创建对象: new ByteArrayOutputStream()
    • 写出数据: write(int), write(byte[])
    • 获取数据: toByteArray()
        FileInputStream fis = new FileInputStream("yyy.txt");
        //在内存中创建了可以增长的内存数组
        ByteArrayOutputStream baos = new ByteArrayOutputStream();           

        int b;
        while((b = fis.read()) != -1) {
            baos.write(b);  //将读取到的数据逐个写到内存中                                                
        }
        //将缓冲区的数据全部获取出来,并赋值给arr数组
        byte[] arr = baos.toByteArray();                                    
        System.out.println(new String(arr,"utf-16"));//可以指定编码码表来转换

        //将缓冲区的内容转换为了字符串,在输出语句中可以省略调用toString方法
        System.out.println(baos.toString());//通过平台默认的码表转为String类                                
        fis.close();
        //baos.close();//因为需要关闭的流在内存以及硬盘之间创建通道的,但baos没创建这个通道不需要关闭

面试题:定义一个文件输入流,调用read(byte[] b)方法,将a.txt文件中的内容打印出来(byte数组大小限制为5)

        // 创建字节输入流,关联yyy.txt
        FileInputStream fis = new FileInputStream("yyy.txt"); 
        // 创建内存输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
        byte[] arr = new byte[5]; // 创建字节数组,大小为5
        int len;
        // 将文件上的数据读到字节数组中
        while ((len = fis.read(arr)) != -1) { 
            // 将字节数组的数据写到内存缓冲区中
            baos.write(arr, 0, len); 
        }
        // 将内存缓冲区的内容转换为字符串打印
        System.out.println(baos); 
        fis.close();

对象操作流(了解)

  • 1.什么是对象操作流
    • 该流可以将一个对象写出, 或者读取一个对象到程序中. 也就是执行了序列化(对象输出流)和反序列化(对象输入流)的操作.
ObjecOutputStream(了解)
  • 1.使用方式
    • 写入的对象必须序列化(需要存储的对象implements Serializable)
    • 写出: new ObjectOutputStream(OutputStream), writeObject()
        // Person必须要要序列化才可以存储implements Serializable
        Person p1 = new Person("张三", 23);//Person已经重写toString()方法
        Person p2 = new Person("李四", 24);
        Person p3 = new Person("王五", 25);
        Person p4 = new Person("赵六", 26);

        ArrayList list = new ArrayList<>();
        list.add(p1);
        list.add(p2);
        list.add(p3);
        list.add(p4);

        ObjectOutputStream oos = new ObjectOutputStream(
                new FileOutputStream("e.txt"));
        oos.writeObject(list);//把整个集合对象一次写出
        oos.close();
ObjectInputStream(了解)
  • 读取: new ObjectInputStream(InputStream), readObject()
        ObjectInputStream ois = new ObjectInputStream(
                new FileInputStream("e.txt"));
        ArrayList list = (ArrayList) 
                ois.readObject();//将集合对象一次读取

        for (Person person : list) {
            System.out.println(person);
        }

        ois.close();

打印流的概述和特点(掌握)

  • 1.什么是打印流
    • 该流可以很方便的将对象的toString()结果输出, 并且自动加上换行, 而且可以使用自动刷出的模式
    • System.out就是一个PrintStream, 其默认向控制台输出信息
            PrintStream ps = System.out;
            ps.println(97); //其实底层用的是Integer.toString(x),将x转换为数字字符串打印
            ps.println("xxx");
            ps.println(new Person("张三", 23));
            Person p = null;
            ps.println(p);//如果是null,就返回null,如果不是null,就调用对象的toString()
  • 2.使用方式
    • 打印: print(), println()
    • 自动刷出: PrintWriter(OutputStream out, boolean autoFlush, String encoding)
    • 打印流只操作数据目的
            PrintWriter pw = new PrintWriter(new FileOutputStream("g.txt"), true);
            pw.write(97);
            pw.print("大家好");
            pw.println("你好");               //自动刷出,只针对的是println方法
            pw.close();

标准输入输出流概述和输出语句(掌握)

  • 1.什么是标准输入输出流(掌握)
    • System.in是InputStream, 标准输入流, 默认可以从键盘输入读取字节数据
    • System.out是PrintStream, 标准输出流, 默认可以向Console中输出字符和字节数据
  • 2.修改标准输入输出流(了解)
    • 修改输入流: System.setIn(InputStream)
    • 修改输出流: System.setOut(PrintStream)
        //改变标准输入流
        System.setIn(new FileInputStream("a.txt")); 
        //改变标注输出流
        System.setOut(new PrintStream("b.txt"));            

        //获取标准的键盘输入流,默认指向键盘,改变后指向文件
        InputStream is = System.in; 
        //获取标准输出流,默认指向的是控制台,改变后就指向文件
        PrintStream ps = System.out;                        

        int b;
        while((b = is.read()) != -1) {
            ps.write(b);
        }
        //System.out.println();//也是一个输出流,不用关,因为没有和硬盘上的文件产生关联的管道
        is.close();//需要关闭的流是与硬盘上建立联系的流,因为不关会耗费内存
        ps.close();

两种方式实现键盘录入(了解)

  • A:BufferedReader的readLine方法。
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));       
        String line = br.readLine();
        System.out.println(line);//br不用关闭,因为这个流现在没有操作文件
  • B:Scanner
        Scanner sc = new Scanner(System.in);
        String line = sc.nextLine();
        System.out.println(line);//sc不用关闭,因为它现在没有操作文件

在实际开发中,需要用到的话首推Scanner这种,因为它功能更为强大(String,int等),BufferedReader只有读字符串的方法

随机访问流概述和读写数据(了解)

  • A:随机访问流概述

    • RandomAccessFile概述
    • RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。
    • 支持对随机访问文件的读取和写入。
  • B:read(),write(),seek()

数据输入输出流(了解)

  • 1.什么是数据输入输出流
    • DataInputStream, DataOutputStream可以按照基本数据类型大小读写数据
    • 例如按Long大小写出一个数字, 写出时该数据占8字节. 读取的时候也可以按照Long类型读取, 一次读取8个字节.
  • 2.使用方式
    • DataOutputStream(OutputStream), writeInt(), writeLong()
        System.out.println("使用FileOutputStream字节输出流写会大的基本类型数据有问题:");
        FileOutputStream fos = new FileOutputStream("h.txt");
        //00000000 00000000 00000011 11100101   int类型997
        //但写的之后自动砍掉前面的三个8位,导致写进去的是11100101
        fos.write(997);//真正写进去的是其二进制的最后8位
        fos.close();

        System.out.println("使用DataOutputStream输出流来写:"); 
        DataOutputStream dos = new DataOutputStream(
                new FileOutputStream("h.txt"));
        dos.writeInt(997);
        dos.writeInt(998);
        dos.writeInt(999);
        dos.close();

        System.out.println("使用DataInputStream输入流来写:");
        FileInputStream fis = new FileInputStream("h.txt");
        int x = fis.read();
        int y = fis.read();
        int z = fis.read();

        System.out.println(x+"  "+y+"  "+z);
        fis.close();

Properties的概述和作为Map集合的使用(了解)

  • A:Properties的概述

    • Properties是Hashtable的子类
    • Properties 类表示了一个持久的属性集。
    • Properties 可保存在流中或从流中加载。
    • 属性列表中每个键及其对应值都是一个字符串(String类)。
  • B:Properties的特殊功能

    • public Object setProperty(String key,String value)
    • public String getProperty(String key)
    • public Enumeration stringPropertyNames()
        Properties prop = new Properties();
        prop.setProperty("name", "张三");
        prop.setProperty("tel", "18912345678");

        //System.out.println(prop);
        //获得存储中的所有key值
        Enumeration<String> en = (Enumeration<String>) prop.propertyNames();
        while(en.hasMoreElements()) {
            String key = en.nextElement();  //获取Properties中的每一个键
            String value = prop.getProperty(key);   //根据键获取值
            System.out.println(key + "="+ value);
        }
  • C:Properties的load()和store()功能
        Properties prop = new Properties();
        //将文件上的键值对读取到集合中
        prop.load(new FileInputStream("config.properties"));    

        prop.setProperty("tel", "18912345678");
        //第二个参数是对列表参数的描述,可以给值,也可以给null
        prop.store(new FileOutputStream("config.properties"), null);
        System.out.println(prop);//打印看看里面的配置信息

第二篇复习连接:
Java基础复习(二) - it菜鸟的飞行梦 - 博客频道 - CSDN.NET

第四篇复习连接:
Java基础复习(四) - it菜鸟的飞行梦 - 博客频道 - CSDN.NET

你可能感兴趣的:(JavaSE学习笔记)