Java基础-20(01)总结,递归,IO流

时间:2022-05-04
本文章向大家介绍Java基础-20(01)总结,递归,IO流,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
1:递归(理解)

(1)方法定义中调用方法本身的现象

举例:老和尚给小和尚讲故事,我们学编程

(2)递归的注意事项;

A:要有出口,否则就是死递归

B:次数不能过多,否则内存溢出

C:构造方法不能递归使用

package cn.itcast_01;
/*
 * 递归:方法定义中调用方法本身的现象
 * 
 * 方法的嵌套调用,这不是递归。
 * Math.max(Math.max(a,b),c);
 * 
 * public void show(int n) {
 *  if(n <= 0) {
 *  System.exit(0);
 *  }
 *  System.out.println(n);
 *  show(--n);
 * }
 * 
 * 注意事项:
 *  A:递归一定要有出口,否则就是死递归
 *  B:递归的次数不能太多,否则就内存溢出
 *  C:构造方法不能递归使用
 * 
 * 举例:
 *  A:从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 *  从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 *  从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 *  从前有座山,山里有座庙,庙里有个老和尚和小和尚,老和尚在给小和尚讲故事,故事是:
 *  ...
 *  庙挂了,或者山崩了
 *  B:学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 *   学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 *  学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 *  学编程  -- 高薪就业 -- 挣钱 -- 娶媳妇 -- 生娃娃 -- 放羊 -- 挣学费
 *  ...
 *  娶不到媳妇或者生不了娃娃 
 */
public class DiGuiDemo {
 // public DiGuiDemo() {
 // DiGuiDemo();
 // }
}

(3)递归的案例:

A:递归求阶乘

package cn.itcast_02;
/*
 * 需求:请用代码实现求5的阶乘。
 * 下面的知识要知道:
 *  5! = 1*2*3*4*5
 *  5! = 5*4!
 * 
 * 有几种方案实现呢?
 *  A:循环实现
 *  B:递归实现
 *  a:做递归要写一个方法
 *  b:出口条件
 *  c:规律
 */
public class 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("5的阶乘是:"+jieCheng(5));
 }
 /*
  * 做递归要写一个方法:
  *  返回值类型:int
  *  参数列表:int n
  * 出口条件:
  *  if(n == 1) {return 1;}
  * 规律:
  *  if(n != 1) {return n*方法名(n-1);}
  */
 public static int jieCheng(int n){
 if(n==1){
 return 1;
 }else {
 return n*jieCheng(n-1);
 }
 }
}

B:兔子发展问题 (斐波那契数列)

package cn.itcast_02;
/*
 * 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
 * 分析:我们要想办法找规律
 *  兔子对数
 * 第一个月:  1
 * 第二个月: 1
 * 第三个月: 2
 * 第四个月: 3 
 * 第五个月: 5
 * 第六个月: 8
 * ...
 * 
 * 由此可见兔子对象的数据是:
 *  1,1,2,3,5,8...
 * 规则:
 *  A:从第三项开始,每一项是前两项之和
 *  B:而且说明前两项是已知的
 * 
 * 如何实现这个程序呢?
 *  A:数组实现
 *  B:变量的变化实现
 *  C:递归实现
 * 
 * 假如相邻的两个月的兔子对数是a,b
 * 第一个相邻的数据:a=1,b=1
 * 第二个相邻的数据:a=1,b=2
 * 第三个相邻的数据:a=2,b=3
 * 第四个相邻的数据:a=3,b=5
 * 看到了:下一次的a是以前的b,下一次是以前的a+b 
 */
public class DiGuiDemo2 {
 public static void main(String[] args) {
 // 定义一个数组
 int[] arr = new int[20];
 arr[0] = 1;
 arr[1] = 1;
 // arr[2] = arr[0] + arr[1];
 // arr[3] = arr[1] + arr[2];
 // ...
 for (int x = 2; x < arr.length; x++) {
 arr[x] = arr[x - 2] + arr[x - 1];
 }
 System.out.println(arr[19]);// 6765
 System.out.println("----------------");
 int a = 1;
 int b = 1;
 for (int x = 0; x < 18; x++) {
 // 临时变量存储上一次的a
 int temp = a;
 a = b;
 b = temp + b;
 }
 System.out.println(b);
 System.out.println("----------------");
 System.out.println(fib(20));
 }
 /*
  * 方法: 返回值类型:int 参数列表:int n 出口条件: 第一个月是1,第二个月是1 规律: 从第三个月开始,每一个月是前两个月之和
  */
 public static int fib(int n) {
 if (n == 1 || n == 2) {
 return 1;
 } else {
 return fib(n - 1) + fib(n - 2);
 }
 }
}

C:递归输出指定目录下所有指定后缀名的文件绝对路径

package cn.itcast_03;
import java.io.File;
/*
 * 需求:请大家把E:JavaSE目录下所有的java结尾的文件的绝对路径给输出在控制台。
 * 
 * 分析:
 *  A:封装目录
 *  B:获取该目录下所有的文件或者文件夹的File数组
 *  C:遍历该File数组,得到每一个File对象
 *  D:判断该File对象是否是文件夹
 *  是:回到B
 *  否:继续判断是否以.java结尾
 *  是:就输出该文件的绝对路径
 *  否:不搭理它
 */
public class FilePathDemo {
 public static void main(String[] args) {
 // 封装目录
 File srcFolder = new File("E:\JavaSE");
 // 递归功能实现
 getAllJavaFilePaths(srcFolder);
 }
 private static void getAllJavaFilePaths(File srcFolder) {
 // 获取该目录下所有的文件或者文件夹的File数组
 File[] fileArray = srcFolder.listFiles();
 // 遍历该File数组,得到每一个File对象
 for (File file : fileArray) {
 // 判断该File对象是否是文件夹
 if (file.isDirectory()) {
 getAllJavaFilePaths(file);
 } else {
 // 继续判断是否以.java结尾
 if (file.getName().endsWith(".java")) {
 // 就输出该文件的绝对路径
 System.out.println(file.getAbsolutePath());
 }
 }
 }
 }
}

D:递归删除带内容的目录(小心使用)

package cn.itcast_03;
import java.io.File;
/*
 * 需求:递归删除带内容的目录
 * 
 * 目录我已经给定:demo
 * 
 * 分析:
 *  A:封装目录
 *  B:获取该目录下的所有文件或者文件夹的File数组
 *  C:遍历该File数组,得到每一个File对象
 *  D:判断该File对象是否是文件夹
 *  是:回到B
 *  否:就删除
 */
public class FileDeleteDemo {
 public static void main(String[] args) {
 // 封装目录
 File srcFolder = new File("demo");
 // 递归实现
 deleteFolder(srcFolder);
 }
 private static void deleteFolder(File srcFolder) {
 // 获取该目录下的所有文件或者文件夹的File数组
 File[] fileArray = srcFolder.listFiles();
 if (fileArray != null) {
 // 遍历该File数组,得到每一个File对象
 for (File file : fileArray) {
 // 判断该File对象是否是文件夹
 if (file.isDirectory()) {
 deleteFolder(file);
 } else {
 System.out.println(file.getName() + "---" + file.delete());
 }
 }
 System.out
 .println(srcFolder.getName() + "---" + srcFolder.delete());
 }
 }
}

2:IO流(掌握)

(1)IO用于在设备间进行数据传输的操作

(2)分类:

A:流向

输入流 读取数据

输出流 写出数据

B:数据类型

字节流

字节输入流

字节输出流

字符流

字符输入流

字符输出流

注意:

a:如果我们没有明确说明按照什么分,默认按照数据类型分。

b:除非文件用windows自带的记事本打开我们能够读懂,才采用字符流,否则建议使用字节流。

(3)FileOutputStream写出数据

A:操作步骤

a:创建字节输出流对象

b:调用write()方法

c:释放资源

B:代码体现:

 FileOutputStream fos = new FileOutputStream("fos.txt");
 fos.write("hello".getBytes());
 fos.close(); 

C:要注意的问题?

a:创建字节输出流对象做了几件事情?

b:为什么要close()?

package cn.itcast_01;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
 * IO流的分类:
 *  流向:
 *  输入流 读取数据
 *  输出流 写出数据
 *  数据类型:
 *  字节流
 *  字节输入流 读取数据 InputStream
 *  字节输出流 写出数据 OutputStream
 *  字符流
 *  字符输入流 读取数据 Reader
 *  字符输出流 写出数据 Writer
 * 
 *  注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。
 * 
 * 需求:我要往一个文本文件中输入一句话:"hello,io"
 * 
 * 分析:
 *  A:这个操作最好是采用字符流来做,但是呢,字符流是在字节流之后才出现的,所以,今天我先讲解字节流如何操作。
 *  B:由于我是要往文件中写一句话,所以我们要采用字节输出流。
 * 
 * 通过上面的分析后我们知道要使用:OutputStream
 * 但是通过查看API,我们发现该流对象是一个抽象类,不能实例化。
 * 所以,我们要找一个具体的子类。
 * 而我们要找的子类是什么名字的呢?这个时候,很简单,我们回想一下,我们是不是要往文件中写东西。
 * 文件是哪个单词:File
 * 然后用的是字节输出流,联起来就是:FileOutputStream
 * 注意:每种基类的子类都是以父类名作为后缀名。
 *  XxxOutputStream
 *  XxxInputStream
 *  XxxReader
 *  XxxWriter
 * 查看FileOutputStream的构造方法:
 *  FileOutputStream(File file) 
 * FileOutputStream(String name)
 *
 * 字节输出流操作步骤:
 *  A:创建字节输出流对象
 *  B:写数据
 *  C:释放资源
 */
public class FileOutputStreamDemo {
 public static void main(String[] args) throws IOException {
 // 创建字节输出流对象
 // FileOutputStream(File file)
 // File file = new File("fos.txt");
 // FileOutputStream fos = new FileOutputStream(file);
 // FileOutputStream(String name)
 FileOutputStream fos = new FileOutputStream("fos.txt");
 /*
  * 创建字节输出流对象了做了几件事情:
  * A:调用系统功能去创建文件
  * B:创建fos对象
  * C:把fos对象指向这个文件
  */
 //写数据
 fos.write("hello,IO".getBytes());
 fos.write("java".getBytes());
 //释放资源
 //关闭此文件输出流并释放与此流有关的所有系统资源。
 fos.close();
 /*
  * 为什么一定要close()呢?
  * A:让流对象变成垃圾,这样就可以被垃圾回收器回收了
  * B:通知系统去释放跟该文件相关的资源
  */
 //java.io.IOException: Stream Closed
 //fos.write("java".getBytes());
 }
}

c:如何实现数据的换行?

d:如何实现数据的追加写入?

package cn.itcast_01;
import java.io.FileOutputStream;
import java.io.IOException;
/*
 * 如何实现数据的换行?
 *  为什么现在没有换行呢?因为你值写了字节数据,并没有写入换行符号。
 *  如何实现呢?写入换行符号即可呗。
 *  刚才我们看到了有写文本文件打开是可以的,通过windows自带的那个不行,为什么呢?
 *  因为不同的系统针对不同的换行符号识别是不一样的?
 *  windows:rn
 *  linux:n
 *  Mac:r
 *  而一些常见的个高级记事本,是可以识别任意换行符号的。
 * 
 * 如何实现数据的追加写入?
 *  用构造方法带第二个参数是true的情况即可
 */
public class FileOutputStreamDemo3 {
 public static void main(String[] args) throws IOException {
 // 创建字节输出流对象
 // FileOutputStream fos = new FileOutputStream("fos3.txt");
 // 创建一个向具有指定 name 的文件中写入数据的输出文件流。如果第二个参数为 true,则将字节写入文件末尾处,而不是写入文件开始处。
 FileOutputStream fos = new FileOutputStream("fos3.txt", true);
 // 写数据
 for (int x = 0; x < 10; x++) {
 fos.write(("hello" + x).getBytes());
 fos.write("rn".getBytes());
 }
 // 释放资源
 fos.close();
 }
}

e:异常处理的字节输出流操作

package cn.itcast_01;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/*
 * 加入异常处理的字节输出流操作
 */
public class FileOutputStreamDemo4 {
 public static void main(String[] args) {
 // 分开做异常处理
 // FileOutputStream fos = null;
 // try {
 // fos = new FileOutputStream("fos4.txt");
 // } catch (FileNotFoundException e) {
 // e.printStackTrace();
 // }
 //
 // try {
 // fos.write("java".getBytes());
 // } catch (IOException e) {
 // e.printStackTrace();
 // }
 //
 // try {
 // fos.close();
 // } catch (IOException e) {
 // e.printStackTrace();
 // }
 // 一起做异常处理
 // try {
 // FileOutputStream fos = new FileOutputStream("fos4.txt");
 // fos.write("java".getBytes());
 // fos.close();
 // } catch (FileNotFoundException e) {
 // e.printStackTrace();
 // } catch (IOException e) {
 // e.printStackTrace();
 // }
 // 改进版
 // 为了在finally里面能够看到该对象就必须定义到外面,为了访问不出问题,还必须给初始化值
 FileOutputStream fos = null;
 try {
 // fos = new FileOutputStream("z:\fos4.txt");
 fos = new FileOutputStream("fos4.txt");
 fos.write("java".getBytes());
 } catch (FileNotFoundException e) {
 e.printStackTrace();
 } catch (IOException e) {
 e.printStackTrace();
 } finally {
 // 如果fos不是null,才需要close()
 if (fos != null) {
 // 为了保证close()一定会执行,就放到这里了
 try {
 fos.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
 }
}