学习java之路之第六周

线程

线程依赖于进程存在!
线程的执行具有随机性!

能够执行的最小单元!(一个线程可以看成进程的某个任务)
360软件---->开启---->开启进程
        同时清理内存---同时查杀病毒

进程

能够调用系统资源的独立单位!(打开计算机任务管理器,查看进程状态)

计算机都是支持多进程,提高CPU的使用率!
开启多个进程的时候,玩游戏的同时可以听音乐,他们并不是同时进行的,而是一点时间片在两个进程之间进行高效切换!

多进程

计算机都是支持多进程,提高CPU的使用率!
开启多个进程的时候,玩游戏的同时可以听音乐,他们并不是同时进行的,而是一点时间片在两个进程之间进行高效切换!

多线程

多线程的意义:

    多个线程在互相抢占CPU执行权!  线程的执行具有随机性!
    1v3打篮球,3个人抢占篮球几率大,不一定(线程执行的是一个随机的)

JVM是多线程的吗?

是一个多线程的,至少有两条线程
main线程----用户线程
gc----->垃圾回收器 开启垃圾回收线程(回收没有更多的对象!)

示例

  1. 线程1,线程2,线程3,线程2在线程1的后面执行,线程3在线程2的后面执行—使用join()方法
public class JoinThreadDemo {
    public static void main(String[] args) {
        //创建三个线程
        JoinThread jt1  = new JoinThread() ;
        JoinThread jt2  = new JoinThread() ;
        JoinThread jt3  = new JoinThread() ;
        //设置线程名称
        jt1.setName("内容1") ;
        jt2.setName("内容2") ;
        jt3.setName("内容3") ;


        //启动线程
        jt1.start();
        //public final void join() throws InterruptedException 等待该线程终止
        try {
            jt1.join();//可能出现的代码   第一个线程等待该线程终止
        } catch (InterruptedException e) {
            e.printStackTrace();  //处理异常: printStackTrace() 打印跟踪
        }

        jt2.start();
        jt3.start();
    }
}

Thread类第一种创建方式(多线程创建方式一)

  • 自定义一个类 继承的自Thread类
  • 重写Thread类的run方法---->完成一些的耗时的操作
  • 在main用户线程中,创建当前这个类对象
  • 开启线程---->不是run方法,run方法它只是一个普通方法(仅仅执行线程里面的内容:读文件/完成io的操作…)
  • 启动线程start()—>jvm是调用run线程的方法,结果是两个同时执行(具有随机性)
public class ThreadDemo {
    public static void main(String[] args) {

        //在main用户线程中,创建当前这个类对象
        MyThread mt = new MyThread() ;
        MyThread mt2 = new MyThread() ;//第二个线程
        //开启线程
       // mt.run();
       // mt.run();

        //执行线程之前,设置线程名称
        mt.setName("线程1") ;
        mt2.setName("线程2") ;


        mt.start();
        //mt.start();//java.lang.IllegalThreadStateException 非法线程状态异常(一个线程不能启动多次)
        mt2.start();


    }
}

多线程的创建方式二

  • 自定义一个类实现Runnable接口,
  • 实现接口里面的run方法—>完成耗时操作
  • 在main用户线程中创建当前这个类的实例—>“资源类对象”
  • 创建线程类Thread对象,然后将3)资源类对象 作为参数传递,启动线程!
public class ThreadDemo {

    public static void main(String[] args) {

        //创建当前这个类对象  "资源类"
        MyRunnable my = new MyRunnable() ;

        //创建两个线程,同时可以给线程设置名称
        //public Thread(Runnable target,String name)
        //Thread类--->代理角色
        Thread t1  = new Thread(my,"t1") ;
        Thread t2  = new Thread(my,"t2") ;

        //分别启动线程
        t1.start();
        t2.start();
    }
}

创建线程的方式3: 线程池(重点,面试中问的多)

线程的状态有几种?

6种状态
Thread类的内部枚举: State
		NEW---新建
		RUNNABLE---运行
		BLOCKED---阻塞
		WAITTING ---死死等待 本质调用wait(0)
		TIMEDWAIITING---超时等待
		TERMINATED---终止(死亡状态)

解决线程安全

验多线程安全问题的标准 (使用标准来看多线程环境是否存在问题,以及解决方案)
1)是否是多线程环境 —>是
2)是否有共享数据 —> 是存在的
3)是否有多条语句对共享数据操作
tickets票:多条语句同时操作
将3)多条语句多共享数据的操作使用同步代码块包起来—解决线程安全问题
synchronized(锁对象){
多条语句对共享数据操作
}

锁对象:可以是任意Java类对象,但是多个线程必须使用的同一个锁对象,否则"锁不住"!

什么是同步方法(非静态)?如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上
权限修饰符 synchronized 返回值类型 方法名(参数列表){

}
锁对象:this—代表类对象的地址值引用
如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)
使用synchronized解决线程安全问题,安全问题解决了,效率低,可能死锁现象

死锁:

  两个线程出现了一种互相等待的情况,A线程等待B线程释放锁,B线程等待A线程释放锁,造成死锁现象!
 举例
          中国人 和美国人吃饭
          一双筷子    一把刀 和一个叉子
         现在
             中国人                 美国人
             一根筷子/一个叉子          一把刀和一根筷子

解决死锁问题—>线程之间的通信必须使用的同一个资源! (生产者和消费者模式思想)

生产者消费者思想

模拟生成者和消费者思想
Student类:学生数据(消费者和生成者需要使用的数据)
SetData类:生成资源类
GetDate类:消费者资源类
按照上面格式:生成者产生数据,消费者使用数据

请添加图片描述

问题1)null—0,生产者和消费者资源类中使用的资源不是同一个对象
改进:生产者和消费者资源类中使用的资源是同一个了
但是现在生产者不断的产生数据,消费者不断地使用数据!

问题2)当我们加入了不断的产生数据,不断的使用数据,while(true)数据出现了紊乱
线程执行具有随机性-----导致多线程不安全
优化改进:需要给里面加入synchronized,将多条对共享数据操作包起来
生产者和消费者资源类都需要加入同步代码块来解决
已经优化:解决线程安全问题了,但是这个数据在控制台 打印的时候 “一次打印很多遍”,cpu一点点时间片可以让某个线程执行多次
继续优化:循环依次打印 数据
高圆圆 35
文章 32
高圆圆 35
文章 32
Java中的等待唤醒机制里面----“信号灯法”

//学生数据
public class Student {
    String name ; //姓名
    int age ;    //年龄

    boolean flag ; //(信号灯标记) 默认false  是否有数据
}

//生产者线程所在的资源类  实现Runnable接口
public class SetData implements Runnable {

    //声明学生类型的变量
    private Student s ;
    private  int x = 0 ;//统计变量
    public SetData(Student s){
        this.s = s ;
    }


    //产生一个学数据
    @Override
    public void run() {

        while (true) { //模拟生成者一直产生数据

            synchronized (s){
                //如果没有数据,等待产数据
                if(s.flag){
                    try {
                        s.wait();//等待会立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(x%2==0){
                    s.name = "高圆圆" ;
                    s.age = 35 ;
                }else{
                    s.name = "文章" ;
                    s.age = 32 ;
                }

                //有数据了,唤醒
                s.flag = true ;
                s.notify(); //唤醒消费者线程,产数据
            }

            x++;
        }


    }
}

//消费者线程所在的资源类 实现Runnable接口
public class GetData implements Runnable{

    //声明学生类型的变量
    private Student s ;
    public GetData(Student s){
        this.s = s;
    }

    //产生一个学生 数据
    @Override
    public void run() {
        //不断的使用数据
        while(true){
            //Student s = new Student() ; //创建
            synchronized (s){

                if(!s.flag){
                    //如果有数据,等待将之前的数据消费掉
                    try {
                        s.wait();//调用 立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(s.name+"-"+s.age);


                //如果没有数据了
                s.flag = false ;
                //通知(唤醒)生产者线程来产数据
                s.notify();
            }

        }

    }
}

//用户线程
public class ThreadMessageTest {
    public static void main(String[] args) {

        //创建一个学生对象---必须同一个
        Student s = new Student() ;

        //创建生产者资源类
        SetData sd = new SetData(s) ;
        //创建消费者资源类
        GetData gd = new GetData(s) ;

        //创建线程-分别操作生成者和消费者
        Thread t1 = new Thread(sd) ;
        Thread t2 = new Thread(gd) ;

        //分别启动线程
        t1.start();
        t2.start();
    }
}

描述Java中的等待唤醒机制

等待唤醒机制—>使用"信号灯法"解决线程安全前提下,造成死锁,多个线程使用同一个资源对象
使用生成者消费者模式思想:
使用生成者不断的产生数据,消费者不断的使用数据(展示数据)
消费者线程等待 先去使用数据,当前没有数据了,需要通知生成者产生数据!

在synchronized同步代码块/同步方法,需要使用监视器(锁)调用wait()和notify(),调用wait()会立即释放锁,完成唤醒的操作!

jdk5以后Lock锁(接口)

和synchronized,有具体的"锁定"操作,指定在某时刻释放锁
Lock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作
实现类:
可重入的互斥锁 java.util.concurrent.locks.ReentrantLock
获取锁: public void lock() 指定的某个时刻
释放锁: public void unlock()
Lock l = …;
l.lock();
try {
// access the resource protected by this lock
} finally {
l.unlock(); //释放锁(系统相关的资源)
}

线程池

会创建一些固定的可重复使用的线程数,会在线程池中,循环利用
当某些线程使用完毕,不会被释放掉,而是归还连接池中,等待下一次再去利用!
成本比普通创建线程方式要大!

java.util.concurrent.Exceutors 工厂类
public static ExecutorService newFixedThreadPool(int nThreads)
创建固定的可重复的线程数的线程池

java.util.concurrent ExecutorService ----->接口的具体实现类 public class ThreadPoolExecutor
Future submit(Callable task):提交异步任务,返回值就是异步任务计算的结果;

上面这个的返回值Future :异步计算的结果—如果现在只是看多个线程是否能够并发的去强转CPU执行权,并没有返回结果
这个返回值可以不用返回!
Callable:接口---->异步任务的执行 类似于 之前Runnable接口

void shutdown():关闭线程池

线程池的特点

1)降低资源销毁,因为线程使用完毕的时候,归还到线程中继续使用!
2)提高线程的维护,还是借助线程池的参数

corePoolSize:核心线程数量
maxmumPoolSize:最大核心线程数
workQueue:阻塞队列
keepAliveTime:生存时间
TimeUnit unit:时间计量单位
handler:拒绝策略:当线程数已经到最大线核心线程池并且同时workeQueue里面队列到达满的状态,线程池会启用拒绝策略! ---->里面也是子实现类---->都是Exceutors的静态内部类
ThreadFactory: 创建线程的工厂------>创建默认的线程池的名称以及后面的序列编号/同时创建线程----->子实现类DefaultThreadFactory—>Exceutors的静态

IO 流

在这里插入图片描述
请添加图片描述

IO流分类

  1. 按流的方向划分
    输入流 ---->读
    输出流 ---->写
  2. 按流的类型划分–同时按方向划分:
  • 字节流
    字节输入流:InputStream—>不能实例化—>具体的子类:针对文件的字节输入流 FileInputStream
    字节输出流:OutputStream—>不能实例化—>具体的子类:针对文件的字节输出流 FileOutputStream
    字节缓冲流(字节高效流)
    字节缓冲输入流:BufferedInputStream
    字节缓冲输出流:BufferedInputStream
  • 字符流
    字符输入流
    字符输出流

使用java.io.File来描述路径形式

File(File parent, String child)
File(String pathname) 推荐第二个
File(String parent, String child)

public class FileDemo {
    public static void main(String[] args) {
        //在磁盘路径的时候 使用\或者使用//代表一个"/"
       // File(File parent, String child)
        File file  = new File("D:\\EE_2211\\day23\\code") ;
        File file2 = new File(file,"Employee.java") ;
        System.out.println(file2);//        D:\EE_2211\day23\code\Employee.java
        System.out.println("----------------------------------") ;
        // File(String pathname) 推荐第二个
        File file3  = new File("D:\\EE_2211\\day23\\code\\Employee.java") ;
        System.out.println(file3);

        System.out.println("----------------------------------") ;
//        File(String parent, String child)
        File file4 = new File("D:\\EE_2211\\day23\\code","Employee.java") ;
        System.out.println(file4);
    }
}

基本功能:

  1. 创建文件/文件夹
  • public boolean createNewFile()throws IOException:创建文件,如果不存在,创建,返回true
  • public boolean mkdir():创建文件夹,如果存在了,则返回false;否则true
  • public boolean mkdirs():创建多级目录,当父目录不存在的时候创建
  1. 判断
  • public boolean isFile():是否是文件 使用居多
  • public boolean isDirectory():是否是文件夹 使用居多
  • public boolean isAbsolute():是否为绝对路径
  • public boolean exists():判断文件或者目录是否存在
  1. 删除
  • public boolean delete():删除由此抽象路径名表示的文件或目录 (删除目录,目录必须为空)
public class FileDemo2 {
    public static void main(String[] args) throws IOException {

        // D:\EE_2211\day23\a.txt
        //描述路径
        File file  = new File("D:\\EE_2211\\day23\\a.txt") ;
        //  public boolean createNewFile()throws IOException
        System.out.println(file.createNewFile());
        System.out.println("----------------------------------");
        File file2 = new File("aaa.txt") ;//没有带盘符,默认当前项目下创建文件
        System.out.println(file2.createNewFile());

        System.out.println("-------------------------------------") ;
        //D:\EE_2211\day23\aaa这个目录
        File file3  = new File("D:\\EE_2211\\day23\\aaa") ;
        System.out.println(file3.mkdir());

        File file4 = new File("ccc\\ddd\\eee") ;
        System.out.println(file4.mkdirs());
        System.out.println(file3.isFile());System.out.println(file3.isDirectory());
        System.out.println(file3.exists());
    }
}

java.io.File:高级功能

public File[] listFiles():获取指定抽象路径表示下的所有的File数组 推荐---->使用File的功能进行判断
public String[] list():抽象路径名表示的目录中的文件和目录。

需求: 获取D盘下所有的以.jpg结尾文件--->输出文件名称
public class FileTest {
    public static void main(String[] args) {

        //1)描述磁盘上抽象路径的表示d://
        File file = new File("D://") ;
        //public String[] list():抽象路径名表示的目录中的文件和目录。
       /* String[] strs = file.list();
        for(String s:strs){
            System.out.println(s) ;
        }*/

        //public File[] listFiles():获取指定抽象路径表示下的所有的File数组  推荐---->使用File的功能进行判断
        File[] files = file.listFiles();
        //遍历之前:非空判断,防止空指针异常
        if(files!=null){
            for(File f :files){
                //f---->有文件/文件夹
                //判断是文件
                if(f.isFile()){
                    //以.jpg结尾
                    if(f.getName().endsWith(".jpg")){
                        System.out.println(f.getName());//String getName():获取File指定的路径的文件或者文件的名称
                    }
                }

            }
        }
    }
}
  • public File[] listFiles(FileFilter filter) 获取File数组的时候,就可以直接获取到指定条件的文件名称或者文件夹
    参数是一个接口:文件过滤器接口

  • boolean accept(File pathname):抽象路径名称所表示的路径是否放在File列表中,取决于返回值 true,否则false,不放在列表中

  • public File[] listFiles(FilenameFilter filter):获取File数组的时候,就可以通过文件名称过滤器按照条件进行过滤
    FilenameFilter接口

  • boolean accept(File dir,String name) :
    参数1:指定的目录
    参数2:文件名称
    返回值: true,将指定指定目录下的文件放在File列表中;否则false

      	需求:获取D盘下所有的以.jpg结尾文件--->输出文件名称
    
public class FileTest2 {
    public static void main(String[] args) {

        //1)描述磁盘上抽象路径的表示d://
        File file = new File("D://") ;
        //public File[] listFiles(FileFilter filter) 获取File数组的时候,就可以直接获取到指定条件的文件名称或者文件夹
       /* File[] files = file.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                //抽象路径名称所表示的路径是否放在File列表中,取决于返回值 true,将这个路径放在列表中,
                // 否则false,不放在列表中
                //获取D盘下所有的以.jpg结尾文件--->输出文件名称

               // System.out.println(pathname);
                return (pathname.isFile() && pathname.getName().endsWith(".jpg"));
            }
        });*/
        //public File[] listFiles(FilenameFilter filter):获取File数组的时候,就可以通过文件名称过滤器按照条件进行过滤
        File[] files = file.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                //创建File对象-->判断File是否为文件
                File f = new File(dir,name) ;//文件放在指定目录中
                //判断f的路径---->指定的文件 并且name文件名称必须以.jpg结尾
                boolean flag1 = f.isFile();
                boolean flag2 = (name.endsWith(".jpg")) ;
                return flag1 && flag2 ;
            }
        });


        //遍历File数组
        if(files!=null){
            for(File f:files){
                System.out.println(f.getName());
            }
        }

    }
}

复制文件

public static void copyFile(String srcFile, String destFile) throws IOException {
        //使用文件字节输入流操作源文件
        FileInputStream fis = new FileInputStream(srcFile) ;
        //使用文件字节输出流操作目的地文件
        FileOutputStream fos = new FileOutputStream(destFile) ;

        //一次读取一个字节
        int len = 0 ;
        while((len=fis.read())!=-1){
            //读一个字节,给fos流对象中写一个字节,写入到目标文件中
            fos.write(len) ;
        }

        //释放资源
        fos.close();
        fis.close();
    }

    //一次读取一个字节数组
    public static void copyFile2(String srcFile,String destFile) throws IOException {
        //使用文件字节输入流操作源文件
        FileInputStream fis = new FileInputStream(srcFile) ;
        //使用文件字节输出流操作目的地文件
        FileOutputStream fos = new FileOutputStream(destFile) ;

        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        //实际字节数
        int len = 0 ;
        while ((len=fis.read(bytes))!=-1){
            //一次读取一个字节数组从字节输入流中,
            //一次写一个字节数组,通过fos写入到destFile中
            fos.write(bytes,0,len);
        }

        //释放
        fos.close();
        fis.close();
    }
}

字节流

字节输出流

在当前项目输出一个文本文本,里面同时写入内容

  1. 创建流对象 ---->将流对象指向"本地文件"—调用系统资源操作文件
    2)写数据
    3)释放流对象相关的资源
public class IODemo {
    public static void main(String[] args) throws IOException {
        //创建字节输出流对象
        //OutputStream抽象类,不能new
        //public FileOutputStream(File file)
        //public FileOutputStream(String pathname):推荐 直接跟路径名称
        FileOutputStream fos = new FileOutputStream("fos.txt") ;

        //写数据
        //public void write(int b)  :写一个字节
        fos.write(97) ;
        fos.write("\r\n".getBytes());
        fos.write(98) ;
      /*  fos.write(99) ;
        fos.write(100) ;
        //public void write(byte[] bytes):写一个字节数组
        byte[] bytes = {65,66,67,68,69,70} ;
        fos.write(bytes);*/


        //释放资源
        fos.close();
    }
}

public FileOutputStream(String name,boolean append) throws FileNotFoundException
创建字节文件输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true

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

//        FileOutputStream fos = new FileOutputStream("fos2.txt") ;
        //public FileOutputStream(String name,boolean append) throws FileNotFoundException
        FileOutputStream fos = new FileOutputStream("fos2.txt",true) ;

        //for循环
        for(int x = 0 ; x < 10;x++){
            fos.write(("hello"+x).getBytes());
            //写一次数据,换一次行
            fos.write("\r\n".getBytes());
        }
        //释放资源
        fos.close();
    }
}

IO流操作的时候,加入异常处理代码格式

开发中 try…catch…finally 使用捕获一次

public class IODemo3 {
    public static void main(String[] args) {

       // method1() ;
        method2() ;
    }

    //方式2:统一try...catch...finally
    public static void method2() {
        FileOutputStream fos = null ;
        try {
            //可能出现问题的代码
             fos = new FileOutputStream("fos3.txt") ;
            //写数据
            fos.write("worldJavaEE".getBytes());
        } catch (IOException e) {
            e.printStackTrace(); //交给jvm,jvm将异常信息打印控制台
        } finally {
            if(fos!=null){
                try {
                    fos.close() ;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    //方式1:分别进行try...catch...  (不推荐)  阅读性差
    public static void method1() {
        //选中这段报红线的代码--->cltr+alt+t--->选则6 try...catch
        FileOutputStream fos = null ;
        try {
            //创建文件字节输出流对象
            fos = new FileOutputStream("fos3.txt") ;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        try {
            //写数据
            fos.write("helloworld".getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }

        //释放资源
        try {
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

字节输入流

InputStream—>读 抽象类
提供子类:FileInputStream:针对文件操作的字节输入流

1)创建文件字节输入流对象
2)读文件
public int read() throws IOException:一次读取一个字节,返回字节数
public int read(byte[] b) throws IOException:一次读取一个字节数组
3)释放资源

public class IODemo4 {
    public static void main(String[] args) throws IOException {
//        1)创建文件字节输入流对象
        //public FileInputStream(String name)throws FileNotFoundException 构造方法
        //FileInputStream fis = new FileInputStream("fis.txt") ;
        //将当前项目下的IODemo3.java文件的内容展示在控制台上
        FileInputStream fis = new FileInputStream("IODemo3.java") ;

//        2)读文件
//        public int read() throws IOException:一次读取一个字节,返回字节数

          //第一次读
       /* int len = fis.read();
        System.out.println(len) ;
        //将len字节---->char类型
       *//* char ch = (char) len;
        System.out.println(ch);*//*
        System.out.println((char)len);

        System.out.println("---------------------------------") ;
        //第二次读取
        len = fis.read() ;
        System.out.println(len) ;
        System.out.println((char)len);
        System.out.println("---------------------------------") ;
        //第三次读
        len = fis.read() ;
        System.out.println(len) ;
        System.out.println((char)len);
        System.out.println("---------------------------------") ;
        //第四次读
        len = fis.read() ;
        System.out.println(len) ;
        System.out.println((char)len);
        System.out.println("-----------------------------------");*/
        //第五次读
       /* len = fis.read() ;
        System.out.println(len) ; //-1:说明已经读取完毕
        System.out.println((char)len) ;*/

        //将上面代码进行优化 while循环改进 ---最终的写法:
        //有一个字节数:从0开始
        int len = 0 ;
        while((len=fis.read())!=-1){ //read()阻塞式方法  //len赋值给流对象调用的读的方法,判断一块在之这里用
            System.out.print((char)len) ;//将数据展示控制台上
        }


//        3)释放资源
        fis.close();
    }
}
/**
 * 传统的io流------>BIO 阻塞式流 :多个线程同时在操作的时候,一个线程在使用io流进行操作时候,其他线程处于阻塞式
 *                NIO:非阻塞式流
 */

请添加图片描述

使用基本字节流一次读取一个字节数组:
public int read(byte[] b) throws IOException:一次读取一个字节数组

需求:将当前项目下的fis2.txt文件的内容原封不动输出控制台
public class IODemo5 {
    public static void main(String[] args) throws IOException {
        //创建一个字节文件输入流对象
        //FileInputStream fis = new FileInputStream("fis2.txt" ) ;
        FileInputStream fis = new FileInputStream("IODemo3.java" ) ;

        //一次读取一个字节数组
        //public int read(byte[] b) throws IOException:一次读取一个字节数组
        //创建一个字节数组
      /*  byte[] bytes = new byte[5] ;
        //第一次读取
        int len = fis.read(bytes) ; //第一次读取总字节数
        System.out.println(len) ;
        //展示内容---->将字节数组----->String
        //String(byte[] bytes,int offerset,int len):每一次都是指定位置开始,读取实际字节数
        System.out.println(new String(bytes,0,len));
        System.out.println("------------------------------------------------") ;
        //第二次读取
        len = fis.read(bytes) ;
        System.out.println(len) ;
        System.out.println(new String(bytes,0,len));
        System.out.println("-------------------------------------------------") ;
        //第三次读取
        len = fis.read(bytes) ;
        System.out.println(len) ;
        System.out.println(new String(bytes,0,len));
        System.out.println("-------------------------------------------------") ;
        //第四次读取
        len = fis.read(bytes) ;
        System.out.println(len) ;
        System.out.println(new String(bytes,0,len));
        System.out.println("-------------------------------------------------") ;
        //第五次读取
        len = fis.read(bytes) ;
        System.out.println(len) ;*/
        //System.out.println(new String(bytes,0,len));

        //通过上面代码:重复性代码,循环改进,而且返回值字节数-1,说明已经读到末尾
        //一次读取一个字节数组,字节数组长度,1024或者1024的整数倍
        byte[] bytes = new byte[1024] ;
        //总字节数
        int len = 0 ;
        while((len=fis.read(bytes))!=-1){ //赋值,判断一块使用
            //将数据展示控制台上
            System.out.println(new String(bytes,0,len));
        }

        //释放资源
        fis.close() ;
    }
}

 需求:将当前项目下的IODemo3.java复制到D:\EE_2211\day24\Copy.java

方式一:使用一次读取一个字节的方式进行复制
方式二:使用一次读取一个字节数数组的方式进行复制

分析:
源文件:当前项目下的IODemo3.java
使用字节输入操作---->源文件FileInputStream(String pathname)
目的地文件:D:\EE_2211\day24\Copy.java
使用字节输出流操作---->目的地文件 FileOutputStream(String pathname)

public class IOTest {
    public static void main(String[] args) throws IOException {
        //使用字节输入操作---->源文件FileInputStream(String pathname)
        FileInputStream fis = new FileInputStream("IODemo3.java") ;
        // 使用字节输出流操作---->目的地文件 FileOutputStream(String pathname)
        FileOutputStream fos = new FileOutputStream("D:\\EE_2211\\day24\\Copy.java") ;

        //方式一:一次读取一个字节
      /*  int len = 0 ;
        while((len=fis.read())!=-1){//不断的再去一次读取字节
            //不断写字节
            fos.write(len); //写入到流对象汇总
        }*/

        //方式二:一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ; //实际字节数
        while((len=fis.read(bytes))!=-1){
            //字节输出流写一个数组到目标文件中
            fos.write(bytes,0,len);
        }

        //释放资源
        fos.close();
        fis.close();
    }
}

复制视频文件,测试 基本字节流一次读取一个字节/一次读取一个字节数组的方式
将指定磁盘路径上的:D:\EE_2211\day24\a.mp4读写复制到当前项目下Copy.mp4

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

        long start = System.currentTimeMillis() ;
        //参数1:源文件地址
       // copyFile("D:\\EE_2211\\day24\\a.mp4","Copy.mp4") ;
        copyFile2("D:\\EE_2211\\day24\\a.mp4","Copy.mp4") ;
        long end = System.currentTimeMillis() ;

        System.out.println("共耗时:"+(end-start)+"毫秒") ;
    }


    /**
     * 基本字节输入流一次读取一个字节
     * @param srcFile 源文件
     * @param destFile 目的地文件
     */
    public static void copyFile(String srcFile, String destFile) throws IOException {
        //使用文件字节输入流操作源文件
        FileInputStream fis = new FileInputStream(srcFile) ;
        //使用文件字节输出流操作目的地文件
        FileOutputStream fos = new FileOutputStream(destFile) ;

        //一次读取一个字节
        int len = 0 ;
        while((len=fis.read())!=-1){
            //读一个字节,给fos流对象中写一个字节,写入到目标文件中
            fos.write(len) ;
        }

        //释放资源
        fos.close();
        fis.close();
    }

    //一次读取一个字节数组
    public static void copyFile2(String srcFile,String destFile) throws IOException {
        //使用文件字节输入流操作源文件
        FileInputStream fis = new FileInputStream(srcFile) ;
        //使用文件字节输出流操作目的地文件
        FileOutputStream fos = new FileOutputStream(destFile) ;

        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        //实际字节数
        int len = 0 ;
        while ((len=fis.read(bytes))!=-1){
            //一次读取一个字节数组从字节输入流中,
            //一次写一个字节数组,通过fos写入到destFile中
            fos.write(bytes,0,len);
        }

        //释放
        fos.close();
        fis.close();
    }
}

字节缓冲流

操作具体的文件使用都是基本字节流FileInputStream/FileOutputStream

字节缓冲输出流/输入流 (高效字节流)

  • BuffedOutputStream/BufferedInputStream:只是提供一个字节缓冲区,本身就是一个字节数组,不会直接操作文件
  • public BufferedOutputStream(OutputStream out):创建一个字节缓冲输出流对象,默认缓冲区大小(足够大)
  • public BufferedInputStream(InputStream in):创建一个字节缓冲输入流对象,默认缓冲大小
public class IO {
    public static void main(String[] args) throws IOException {

//        bufferedWrite();//使用字节缓冲流写数据
          bufferedRead() ;
    }

    //读取当前项目下的bos.txt文件,展示控制台上
    public static void bufferedRead() throws IOException {
        // public BufferedInputStream(InputStream in):创建一个字节缓冲输入流对象,默认缓冲大小

        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream("bos.txt")) ;  //缓冲大小8192长度,将读取的内容缓冲这个缓冲区中

        //读取方式:一次读取一个字节
       /* int by = 0 ;//实际字节数
        while((by=bis.read())!=-1){
            System.out.print((char)by);
        }*/
        //要么一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=bis.read(bytes))!=-1){
            System.out.println(new String(bytes,0,len));
        }

        bis.close();
    }

    public static void bufferedWrite() throws IOException {
        //public BufferedOutputStream(OutputStream out)
        FileOutputStream fos = new FileOutputStream("bos.txt") ;
        BufferedOutputStream bos = new BufferedOutputStream(fos) ;
        /**
         *构造方法的原码:
         * public BufferedOutputStream(OutputStream out) {
         *         this(out, 8192);  //调用本类的带两个参数的有参构造
         *     }
         * public BufferedOutputStream(OutputStream out, int size) {
         *         super(out);
         *         if (size <= 0) {
         *             throw new IllegalArgumentException("Buffer size <= 0");
         *         }
         *         buf = new byte[size];  //byte[] buf = new byte[8192] ;
         *     }
         */

        //写数据
        bos.write("hello高圆圆".getBytes());
        bos.write("\r\n".getBytes());
        bos.write("helloworld".getBytes());
        bos.write("\r\n".getBytes());
        bos.write("hellojavaEE".getBytes());
        bos.write("\r\n".getBytes());
        //关闭,刷新
        bos.flush();

        //释放资源
        bos.close();
    }
}

针对视频文件复制

基本字节流
给定12M左右的视频文件····一次读取一个字节方式:共耗时:263452毫秒
给定12M左右的视频文件····一次读取一个字节方式:共耗时:345毫秒
字节缓冲流的方式
使用字节缓冲流的方式·····一次读取一个字节 共耗时:2403毫秒
使用字节缓冲流的方式·····一次读取一个字节数组 共耗时:195毫秒

字节流—>BufferedInputStream/BufferedOutputStream—字节高效流(使用多)

public class CopyFileTest {
    public static void main(String[] args) throws IOException {
        //D:\EE_2211\day24\a.mp4---复制到 当前项目copy.mp4
        long start = System.currentTimeMillis() ;
       // copyFile("D:\\EE_2211\\day24\\a.mp4","copy.mp4") ;
        copyFile2("D:\\EE_2211\\day24\\a.mp4","copy.mp4") ;
        long end = System.currentTimeMillis() ;
        System.out.println("共耗时:"+(end-start)+"毫秒");
    }

    //字节缓冲流一次读取一个字节数组
    public static void copyFile2(String srcFile, String destFile) throws IOException {
        //创建字节缓冲输入流对象
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(srcFile)) ;
        //创建字节缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destFile)) ;

        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);

        }
        bos.flush() ;//强制刷新缓冲字节  (网络中 TCP传输协议,这种场景刷新,客户端文件---传给服务器端)

        //释放资源
        bos.close();
        bis.close();
    }

    //字节缓冲流一次读取一个字节
    public static void copyFile(String srcFile, String destFile) throws IOException {
        //创建字节缓冲输入流对象
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(srcFile)) ;
        //创建字节缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destFile)) ;

        //一次读取一个字节
        int by = 0 ;
        while((by=bis.read())!=-1){
            //写一个字节
            bos.write(by) ;
        }
        //释放资源
        bos.close();
        bis.close();
    }
}

字符流

字符流是在字节流后出现,如果是文本文本进行操作,优先使用字符流!

  • Writer:具体的子类

public OutputStreamWriter(OutputStream out):
字符转换输出流(可以将基本字节输出流转换成字符输出流),平台默认的字符集编码(idea,utf-8)
public OutputStreamWriter(OutputStream out,String charsetName):
字符转换输出流 ,指定一个编码字符集

  • 写的功能
    • void write(char[] cbuf)写入一个字符数组。
    • abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
    • void write(int c) 写一个字符
    • void write(String str)写一个字符串
    • void write(String str, int off, int len) :写入字符串的一部分
  • Reader:(抽象类)具体子类

public InputStreamReader(InputStream in):创建字符转换输入流,以平台默认字符集解码
public InputStreamReader(InputStream in,String charsetName):
创建字符转换输入流对象,指定字符集解码

  • read的功能
    • public int read(char[] cbuf):读取字符数组
    • public int read():读一个字符

InputStreamReader/OutputStreamWriter:字符转换流弊端:代码格式复杂,不能直接操作文件!

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

        //write() ;
        read() ;
    }

    //使用字符转换流读取项目下osw.txt,展示在控制台上
    private static void read() throws IOException {
        //public InputStreamReader(InputStream in,String  charsetName):
        //  创建字符转换输入流对象,指定字符集解码
        /*InputStreamReader isr = new InputStreamReader(
                new FileInputStream("osw.txt"),"gbk") ;//解码gbk*/
        /*InputStreamReader isr = new InputStreamReader(
                new FileInputStream("osw.txt"),"utf-8") ;*///解码utf-8
        // public InputStreamReader(InputStream in):创建字符转换输入流,以平台默认字符集解码
        InputStreamReader isr = new InputStreamReader(
                new FileInputStream("osw.txt"));

        //read的功能
        //一次读取一个字符
        int by = 0 ;//字符数
        while((by=isr.read())!=-1){
            //展示控制台
            System.out.print((char)by);

        }

        //释放资源
        isr.close();
    }

    //给当前项目下输出文件,同时写入内容--->字符缓冲输出流
    private static void write() throws IOException {
        //public OutputStreamWriter(OutputStream out):
        OutputStreamWriter osw = new OutputStreamWriter(
                new FileOutputStream("osw.txt")) ;//默认字符集编码utf-8

        //写
        // void write(char[] cbuf)写入一个字符数组。
        char[] chs  =  {'a','b','c','d','e','f'} ;
        osw.write(chs);
        //abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
        osw.write(chs,0,2);
        //void write(int c)  写一个字符--- 将int数据类型--->ASCII码表 转换成对应的字符
        osw.write(101);
        //void write(String str)写一个字符串
        osw.write("高圆圆") ;

        //刷新
        osw.flush() ;
        //释放
        osw.close();

    }
}

public InputStreamReader(InputStream in)
public OutputStreamWriter(OutputStream out)
上面字符转换流使用的时候,无法直接直接操作具体文件,里面包装一层字节流操作,书写格式繁琐!

提供了他们具体的子类 —字符转换流的便捷类,跟idea平台默认字符集一致

  • FileReader(File/String pathname)
  • FileWriter(File/String pathname)
  • FileWriter(File/String pathname,boolean append):第二个参数为true,追加内容

字符流针对文件(使用高级记事本打开能读懂的),使用字符流操作

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

        //将当前项目下的FileReader_WriterDemo.java复制到D:\EE_2211\day25\resource\copy.java
        //创建FileReader操作源文件
        FileReader fr = new FileReader("IODemo.java") ;
        //创建Filewriter写数据
        FileWriter fw = new FileWriter("D:\\EE_2211\\day25\\resource\\copy.java") ;

        //一次读取字符/字符数组
        char[] chs = new char[1024] ;
        int len = 0 ;
        while((len=fr.read(chs))!=-1){
            //写字符数组,每次0开始,写入实际字符数
            fw.write(new String(chs,0,len)) ;
            fw.flush();
        }
        //关闭
        fw.close() ;
        fr.close() ;
    }
}

使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐!)

读写复制

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

        //创建字符缓冲输入流对象-->读
        BufferedReader br = new BufferedReader(
                new FileReader("IODemo.java")) ;
        //创建字符缓冲输出流对象-->写
        BufferedWriter bw = new BufferedWriter(
                new FileWriter("D:\\Demo.java")) ;

        //特有方式:一次读取一行
        String line = null ;
        while((line=br.readLine())!=null){
            //写一行
            bw.write(line) ;
            bw.newLine() ;
            bw.flush() ;//刷新
        }
        //释放资源
        bw.close();
        br.close();
    }
}

字符缓冲流

BufferedReader:字符缓冲输入流
BufferedWriter:字符缓冲输出流
他们不能直接操作文件,提供缓冲区让读写效率更高,特有方式
BufferedReader一次读取一行/可以作为键盘录入(录入一行字符串内容)

字符流针对文本文件(记事本打开能看懂的)–>字符流读写复制

  • 字符转换流InputStreamReader/OutputStreamWriter 一次读取一个字符/一次读取一个字符数组
  • 使用字符转换流的便捷类FileReader/FileWriter 可以直击操作文件 一次读取一个字符/一次读取一个字符数组
  • 使用字符缓冲流BufferedReader/BufferedWriter: 一次读取一个字符/一次读取一个字符数组
  • 使用字符缓冲流BufferedReader/BufferedWriter :一次读取一行特有方式(推荐!)

读写复制

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


       // write() ;
        read() ;

    }

    //BuffereReader:字符缓冲输入流 ,将当前项目bw.txt读取出来,展示控制台
    private static void read() throws IOException {
        //BufferedReader(Reader in)
        //创建一个字符缓冲输入流对象
        BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;

        //读的方式:一次读取一个字符/一次读取一个字符数组 (传统方式)
        //BufferedReader的特有功能
        //public String readLine() throws IOException:一次读取一行

      /*  //第一次读
        String line = br.readLine();
        System.out.println(line) ;
        //第二次读
        line = br.readLine() ;
        System.out.println(line) ;
        //第三次读
        line = br.readLine() ;
        System.out.println(line);
        //第四次读
        line = br.readLine() ;
        System.out.println(line);

        //第五次读
        line = br.readLine() ;
        System.out.println(line);*/
        //一次读取一行的
        String line = null ; //读取的实际内容
        while((line=br.readLine())!=null){//readLine() :阻塞式方法
            if("886".equals(line)){
                break ;
            }
            //展示控制台
            System.out.println(line) ;
        }



    }
    //BufferedWriter:字符缓冲输出流

    private static void write() throws IOException {
        //创建一个字符缓冲输出流对象
        //public BufferedWriter(Writer out)
        BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt")) ;

        //BufferedWriter的特有功能
        //写的功能---使用最多就是写public void write(String str)
        bw.write("hello");
        //public void newLine() throws IOException
        bw.newLine();
        bw.write("world") ;
        bw.newLine();
        bw.write("java");
        bw.newLine();
        bw.write("高圆圆");
        bw.newLine();

        //释放资源
        bw.close();
    }
}

BufferedReader(Reader in):字符缓冲输入流

也可以键盘录入
main()里面String[] 可以键盘录入 ,录入字符串
Scanner以及提供的nextXXX()
BufferedReader

public class BufferedDemo2 {
    public static void main(String[] args) throws IOException {
        //键盘录入---->Scanner(InputStream in) :里面参数使用字节输入流

        //BufferedReader(Reader in):字符缓冲输入流




        //InputStream in = System.in ; //标准输入流---等待录入
        //创建字符输入流:Reader抽象类
        //InputStreamReader是具体的子类 构造方法InputStreamReader(InputStream in )
       // Reader reader = new InputStreamReader(in) ;

        //创建一个字符缓冲输入流对象
        //BufferedReader br = new BufferedReader(reader) ;

        //一步走
        BufferedReader br  = new BufferedReader(
                new InputStreamReader(System.in)) ;

        //提示并录入
        System.out.println("请您输入一个字符串:");
        //利用BufferedReader一次读取一行
        String line = br.readLine() ;
        System.out.println("您录入的数据是:"+line) ;

    }
}
练习

BufferedReader/BufferedWriter 使用字符缓冲流一次读取一行特有方式(推荐!)

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

        //创建字符缓冲输入流对象-->读
        BufferedReader br = new BufferedReader(
                new FileReader("IODemo.java")) ;
        //创建字符缓冲输出流对象-->写
        BufferedWriter bw = new BufferedWriter(
                new FileWriter("D:\\Demo.java")) ;

        //特有方式:一次读取一行
        String line = null ;
        while((line=br.readLine())!=null){
            //写一行
            bw.write(line) ;
            bw.newLine() ;
            bw.flush() ;//刷新
        }
        //释放资源
        bw.close();
        br.close();
    }
}

用IO流实现登录注册

使用IO流的方式模拟用户的注册和登录
1)提供User类---->username,password都是String类型,用户名和密码
2)提供UserDao接口---->针对用户操作数据访问接口
                        void resiter(User user) ;
                        boolean isLogin(String username,String password) ;
3)提供UserDaoImpl---->将两个具体实现
4)UserTest---------->进行测试
                  1 注册 2 登录 3 退出...

容器---->存储数据,方便取出
集合去操作
IO流:永久存储一个文件(耗时)

数据库存储系统—最终存储方式---->通过Java操作—>存储数据库 JDBC
关系型数据库
非关系数据库

目录结构

user.txt
src

test——>UserTest.java
pojo——>User.java
dao——>UserDao.java

impl——>UserDaoImpl.java

用户实体类

public class User {
    private String username ;//用户名
    private String password;//密码

    public User() {
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

针对用户操作的数据访问接口

public interface UserDao {

    /**
     * 注册用户
     * @param user 注册用户实体
     */
    void register(User user) ;

    /**
     * 用户登录功能
     * @param username 用户名
     * @param password 密码
     * @return 返回登录是否成功,true,成功;false,不成功
     */
    boolean isLogin(String username,String password) ;

}

针对用户数据访问接口实现

public class UserDaoImpl  implements UserDao {

    //创建一个File对象--->表示一个路径的抽象形式
    private static File file = new File("user.txt") ;

    //静态代码块
    static {
        if(!file.exists()){ //不存在创建
            //创建文件
            try {
                file.createNewFile() ;
            } catch (IOException e) {
                //e.printStackTrace(); //jvm将异常信息打印在控制台上
                //自己处理
                System.out.println("创建文件失败!");
            }
        }
    }

    //user.txt
    //张三=123
    //李四=123456

    /**
     * 用户登录功能
     * @param username 用户名
     * @param password 密码
     * @return 返回登录是否成功,true,成功;false,不成功
     */
    @Override
    public boolean isLogin(String username, String password) {
        //登录的时候,需要读当前项目下user.txt
        //创建字符缓冲输入流BufferedReader
        //假设
        // 定义变量
        boolean flag = false ;
        try {
            BufferedReader br = new BufferedReader(
                    new FileReader(file)) ;
            //一次读取一行
            String line = null ;
            while((line=br.readLine())!=null){

                //判断
                //通过= 拆分出 文件中  "用户名=密码"
                String[] strs = line.split("=");
                //strs[0]   用户名
                //strs[1]   密码
                if(strs[0].equals(username) && strs[1].equals(password)){
                    //修改标记
                    flag =true;
                    break ;
                }
            }

        } catch (FileNotFoundException e) {
           // e.printStackTrace();
            System.out.println("文件找不到");
        } catch (IOException e) {
           // e.printStackTrace();
            System.out.println("读取文件失败");
        }
        return flag;
    }

    /**
     * 注册用户
     * @param user 注册用户实体
     */
    @Override
    public void register(User user) { //录入用户信息

        try {
            //在当前项目下输出一个文件user.txt,录入用户名和密码的还是,将用户名和密码写入user.txt中
            //约定一种格式 "用户名=密码" 将内容写入
            //创建一个字符缓冲输出流对象,写内容
            //FileWriter(File/String pathname,boolean append):第二个参数为true,追加内容
            BufferedWriter bw = new BufferedWriter(
                    new FileWriter(file,true));

            //写数据
            //约定一种格式 "用户名=密码" 将内容写入
            bw.write(user.getUsername()+"="+user.getPassword());
            bw.newLine();
            bw.flush();

        } catch (IOException e) {
            //e.printStackTrace();
            System.out.println("注册失败");
        }
    }
}
public class UserTest {
    public static void main(String[] args) {

        while (true){
            System.out.println("------------------------欢迎访问-----------------------------");
            System.out.println("1  登录 , 2  注册  , 3 退出");
            //创建键盘录入对象
            Scanner sc = new Scanner(System.in) ;
            System.out.println("请输入您的选择:") ;
            String choiceNum = sc.nextLine() ;
            //创建接口对象
            UserDao ud = new UserDaoImpl() ;

            switch (choiceNum){
                case "1":
                    System.out.println("--------------进入登录----------------");
                    System.out.println("请输入用户名:");
                    String name = sc.nextLine() ;
                    System.out.println("请输入密码:");
                    String pwd = sc.nextLine() ;
                    //调用功能
                    boolean flag = ud.isLogin(name, pwd);
                    if(flag){
                        System.out.println("恭喜您,登录成功");
                        System.exit(0);
                    }else{
                        System.out.println("对不起,用户名或者密码输入错误");
                    }
                   break ;
                case "2":
                    System.out.println("--------------进入注册----------------");
                    System.out.println("请输入用户名:");
                    String username = sc.nextLine() ;
                    System.out.println("请输入密码:");
                    String password = sc.nextLine() ;
                    //封装user
                    User user = new User() ;
                    user.setUsername(username) ;
                    user.setPassword(password);
                    //调用功能
                    ud.register(user) ;
                    System.out.println("恭喜您,注册成功!");
                    break;
                case "3":
                default:
                    System.out.println("谢谢光临,欢迎下次使用!") ;
                    System.exit(0);
            }
        }

    }
}

递归思想

请添加图片描述
递归:方法调用本身的一种现象! 不是方法嵌套方法
java.lang.Math.max(10,Math.max(20,15)) ;

伪代码
public void show(int n){//5
while(n<0){
break ;
}
System.out.println(n) ;//5
show(n–);
}

方法递归:
1)需要有方法
2)有一定规律
3)有方法结束的条件(出口条件),否则 “死递归”
构造方法没有递归

需求:求5的阶乘
使用求阶乘思想完成
使用递归思想

解决问题的思路:
	将问题1--->进行分解若干小问题
		问题11
		问题12
		 ...
public class DiGuiDemo {

   /* public DiGuiDemo(){
        DiGuiDemo();
    }*/
   public static void main(String[] args) {

       //使用求阶乘思想完成
       //定义一个结果变量
       int jc = 1 ;
       for(int x = 2 ;x<=5 ; x ++){
           jc*=x ;
       }
       System.out.println("5的阶乘是:"+jc);

       System.out.println("-------------------------------------") ;
       System.out.println("5的阶乘是:"+jieCheng(5));
   }


    //定义求5的阶乘的方法
    private static int jieCheng(int n) {//5
       if(n==1){
           return  1 ;
       }else {
           //如果不是1
           //5*调用方法名(5-1)
           return n * jieCheng(n-1) ;
           //5 *4*3*2*jiecheng(1)
       }
    }
}

不死神兔

有一个很有名的数学逻辑题叫做不死神兔问题。

有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?

规律:
兔子的对数
第一个月:1
第二个月:1
第三个月:2
第四个月:3
第五个月:5
第六个月:8
底七个月:13

第一个月和第二个月兔子的对数是1
从第三个月开始,每一月兔子对数是前两个月兔子对数之和!

使用a,b代表相邻两个月兔子的对数
第一个,第二个月 a=1,b=1
第二月,第三个月 a=1,b=2
第三个月,第四个月 a=2,b=3
第四个月,第五个月 a=3,b=5

public class Test1 {
    public static void main(String[] args) {
        //数组的方式去实现
        //创建一个数组:动态初始化
        int[] arr = new int[20] ; //第二十个月
        //第一个月和第二个都是1
        arr[0] = 1 ;
        arr[1] = 1 ;
        //从第三个月开始,每一月兔子对数是前两个月兔子对数之和!
        for(int x = 2 ;x<arr.length;x++){
            arr[x] = arr[x-1] + arr[x-2] ;
        }
        //输出最后一个元素
        System.out.println("第二十个月兔子对数:"+arr[19]); //6765
        System.out.println("-----------------------------------------------------") ;

        //递归:定义一个方法

        //long time = System.currentTimeMillis() ;
        System.out.println("第二十个月的兔子的对数是:"+getRabbit(20));
       // long end = System.currentTimeMillis();
       // System.out.println("耗时"+(end-time)+"毫秒");


    }
    //定义一个方法
    public static int getRabbit(int n){//代表的第几个月
        //第一个月和第二个月兔子的对数是1---->方法递归的出口条件
        if(n==1 || n==2){
            return  1;
        }else {
            //从第三个月开始,每一个月兔子对数是前两个月兔子对数之和!
            return getRabbit(n-1)+getRabbit(n-2) ;
        }
    }

}

面试题若干

  1. Java能够直接创建多线程吗?
    创建线程---->需要创建进程---->需要使用系统资源创建进程
    Java是不能够直接操作系统资源的,底层语言C是可以操作系统的
    Jdk提供了Thread类,里面有个start()---->执行线程—底层非Java语言实现的
  2. 为什么wait()和notify(),线程等待,线程唤醒为什么定义Object类中?
    这两个方法都是监视器(锁)有关系,锁对象可以是任意Java类型(jdk提供 任何类,自定义的类),Object代表所有类的父类,任意Java对象可以使用Object,所以这些都定义在Object类中
  3. wait()和sleep()的区别?
  • 来源不同
    • wait()来自于Object,被锁对象调用的
    • sleep()来自于Thread,线程睡眠,通过线程对象调用的
  • 是否会释放锁
    • wait()方法的调用,会立即释放锁,才能通过notify()唤醒对方线程,达到同步安全
    • sleep()只是Thread类的普通方法,跟锁没有关系,睡眠中,线程处于阻塞状态,当线程睡眠时间到,线程继续执行
  • 共同点都会抛出异常 throws InterruptedException:中断异常
  1. throw和throws的区别?
  • throws和throw共同点都是抛出的异常!
throws:
	1)抛出是在方法声明上抛出
	public static Date string2Date(String source,String pattern) throws ParseException,Exception{
        return new SimplateDateFormat(pattern).parse(source) ;
        
        //String dateStr ="2022-11-22" ;
        //使用SimplateDateFormat里面传递的模式 "yyyy年MM月dd日",跟上面的格式不一致
	}
	2)throws的后面跟的异常类名,可以跟多个异常类名,中间逗号隔开
	3)针对throws抛出的方法处理,谁调用这个方法,谁必须处理! (处理方式---交给调用者,继续throws或者try..catch...finally)
	4)throws它表示抛出异常的可能性
throw:
	1)抛出是在方法体语句中
	2)后面跟是异常对象名  throw new XXXEception(),只能某个异常对象名
	3)throw抛出的处理---交个方法中逻辑语句处理 if语句
	4)它表示抛出异常的肯定性,执行某段代码一定会有这个异常!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱学Java的小宇宙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值