一、递归
(一)练习
计算5的阶乘:5! = 5 * 4 * 3 * 2 * 1
代码示例
//计算5的阶乘:5! = 5 * 4 * 3 * 2 * 1
public class Demo01_Exercise {
public static void main(String[] args) {
System.out.println(factorial(5));
}
public static int factorial(int i) {
//其他数字相乘
if(i > 1) {
return i * factorial(i - 1);
}
//1相乘
if(i == 1) {
return 1;
}
return 0;
}
public static void test() {
int result = 1;
for (int i = 5; i >= 1; i--) {
result *= i;
}
System.out.println(result);
}
}
(二)递归的概述
1、递:传递,逐渐的、一个接一个的传递;归:回归,回到原始的简单的状态
2、一种从大到小、从复杂到简单的过程
3、递归:方法自己调用自己,解决的是一个比较复杂的问题,复杂的问题是基于简单的问题解决的基础上的,经过非常少的步骤,就可以解决这个复杂的问题。方法在自己调用自己的过程中,调用的总体逻辑不变,但是解决问题的规模越来越小(参数越来越小),一直到不需要递归的方式,也到能容易解决这个问题为止,就不需要再进行递归了。
4、递归代码的特点:
(1)方法自己调用自己:总体逻辑不变,但是规模在缩小,由于自己调用自己,所以功能都要单独的定义为一个方法
(2)方法中的业务逻辑有两个分支:
1)自己调用自己的分支:业务规模还比较大,无法直接解决问题,使用递归
2)不需要自己调用自己的分支:规模已经足够小,小到不需要(不能)使用递归,仅仅一个简单的操作就能完成
(3)每次递归的时候,朝着规模逐渐减小的方向、朝着递归不能进行的方向
(三)递归的内存图
(四)练习
有一个数列:斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55
写一段代码,当你指定一个项数的时候,能求出该项的具体值是多少
代码示例
/**
* 有一个数列:斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
写一段代码,当你指定一个项数的时候,能求出该项的具体值是多少
*
* 两个分支:
* 不需要递归:第一项和第二项
* 需要递归:等价条件:前两项的和是本项
*
*
* @author Zihuatanejo
*
*/
public class Demo02_Exercise {
public static void main(String[] args) {
System.out.println(getResult(11));
}
public static int getResult(int n) {
if(n == 1 || n == 2) {
return 1;
}
if(n > 2) {
return getResult(n - 2) + getResult(n - 1);
}
return 0;
}
}
(五)递归的注意事项
1、递归效率较低,因为方法需要不断进出栈
2、递归算法比较浪费栈内存,栈内存本身比较小,很容易耗尽栈内存,如果栈内存被耗尽,就无法执行方法,并且会出现错误:StackOverFlowError栈内存溢出
3、国外有一个网站:StackOverFlow,国外的专业版知乎
4、好处:思路比较简单,复杂的问题能用很简单的方式解决
5、递归能够解决的问题,都具有非递归的解决方式,只是解决起来更加麻烦
二、File类型
(一)概述
1、File类型:用于表示一个文件或者文件夹的抽象路径
2、路径:用于描述文件或者文件夹所在位置的字符串
3、路径分类:
(1)绝对路径:从根目录开始的路径
1)windows系统:根目录的起始就是盘符
2)Linux系统:/就是根目录,从/开始的路径就是绝对路径
(2)相对路径:相对于某个路径而言,例如相对路径1.txt,之于:【E:\新建文件夹\a\1.txt】和之于【C:\Users\Zihuatanejo\Desktop\1.txt】是不同的两个路径
(二)File类型的构造方法
1、File(String pathname) 将一个字符串表示的路径封装为File对象
2、File(File parent, String child) 将父级路径和子级路径封装成一个File对象,对象中的路径是父级路径加子级路径
3、File(String parent, String child) 将父级路径和子级路径封装成一个File对象,对象中的路径是父级路径加子级路径
代码示例
import java.io.File;
public class Demo03_FileConstructor {
public static void main(String[] args) {
/*File path = new File("E:\\1019Java\\day18\\笔记\\Day18笔记.docx");
System.out.println(path);
File path1 = new File("E:/019Java/day18/笔记/Day18笔记.docx");
System.out.println(path1);*/
File file1 = new File("E:\\a");
File file2 = new File(file1, "1.txt");
System.out.println(file2);
File file = new File("C:", "User");
System.out.println(file);
}
}
(三)File类型的创建方法
1、createNewFile() 当且仅当File对象表示的文件路径的文件不存在时,创建一个新的空文件,如果创建成功就返回true
2、mkdir() 只能创建单个目录。当且仅当File对象抽象路径表示的文件夹不存在的时候,创建文件夹,并且返回true。当要创建的目录所在的父级目录不存在的时候,创建失败
3、mkdirs() 可以创建嵌套目录。在创建嵌套目录时,如果父级目录部分或者全部不存在时,都可以完成创建
代码示例
import java.io.File;
import java.io.IOException;
public class Demo04_CreateMethod {
public static void main(String[] args) throws IOException {
/*File file = new File("D:\\a.txt");//对象仅仅表示路径
//createNewFile()
System.out.println(file.createNewFile());*/
File file1 = new File("a");//在Eclipse中,所有的相对路径都是相对当前工程而言
//System.out.println(file1.mkdir());
//在当前工程下创建文件夹 a/b/c/d
File path = new File(file1, "b/c/d");
//System.out.println(path);
//System.out.println(path.mkdir());
System.out.println(path.mkdirs());
}
}
(四)创建方法练习
在D盘下的a/b/c/d中创建一个文件,名称叫做HelloWorld.txt
代码示例
import java.io.File;
import java.io.IOException;
/**
* 在D盘下的a/b/c/d中创建一个文件,名称叫做HelloWorld.txt
*
* @author Zihuatanejo
*
*/
public class Demo05_CreateExercise {
public static void main(String[] args) throws IOException {
//1.创建File对象,表示D盘下的a/b/c/d目录
File dirPath = new File("D:\\a\\b\\c\\d");
//2.创建嵌套文件夹
dirPath.mkdirs();
//3.使用构造方法:File(File parent, String child) 创建新的File对象表示文件的路径
File filePath = new File(dirPath, "HelloWorld.txt");
//4.创建文件
filePath.createNewFile();
}
}
(五)File类型的删除方法
1、delete() 删除路径指定的文件或者文件夹
2、注意事项:
(1)使用该方法删除的文件夹只能是空文件夹,无法删除非空文件夹
(2)使用该方法删除的内容不走回收
代码示例
import java.io.File;
public class Demo06_DeleteMethod {
public static void main(String[] args) {
/*//1.创建File对象,表示待删除的文件(或者文件夹)
File filePath = new File("D:\\a\\b\\c\\d\\HelloWorld.txt");
//2.调用delete方法删除指定文件
System.out.println(filePath.delete());*/
/*File dirPath = new File("delete");
System.out.println(dirPath.delete());*/
File file = new File("D:\\a");
System.out.println(file.delete());
}
}
(六)File类型的重命名方法
1、renameTo(File dest) 将调用者对象表示的文件使用参数对象表示的新名称重新命名
2、注意事项:
(1)在同路径下,该方法仅仅是重命名
(2)在不同路径下,该方法是剪切并且重命名
代码示例
import java.io.File;
public class Demo07_RenameToMethod {
public static void main(String[] args) {
//renameTo(File dest) 将调用者对象表示的文件使用参数对象表示的新名称重新命名
//1.创建File对象,表示指定文件
//File file = new File("a.txt");
//2.创建File对象,表示新文件名称
//File file1 = new File("b.txt");
//System.out.println(file.renameTo(file1));
File file = new File("D:\\a.txt");
File file1 = new File("U:\\b.txt");
System.out.println(file.renameTo(file1));
}
}
(七)File类型的判断功能
1、exists() 测试调用者表示的抽象路径名是否存在
2、isFile() 测试调用者抽象路径表示的文件是否是一个标准文件
3、isDirectory() 测试调用者对象表示的路径是否为一个文件夹
代码示例
import java.io.File;
public class Demo08_QueryMethod {
public static void main(String[] args) {
File file = new File("a");
File file2 = new File("b.txt");
System.out.println(file.isFile());
System.out.println(file2.isFile());
System.out.println(file.isDirectory());
System.out.println(file2.isDirectory());
}
public static void test1() {
File file = new File("a.txt");
File file2 = new File("b.txt");
System.out.println(file.exists());
System.out.println(file2.exists());
}
}
(八)File类型的获取功能
1、getAbsolutePath() 获取当前File表示的内容的绝对路径
2、getName() 获取当前File对象路径表示的文件或者文件夹的名称
3、length() 获取File对象指代的文件的长度(所占字节个数)。注意:该方法只能用于统计文件大小,无法统计文件夹的大小
4、String[] list() 将File对象表示的文件夹下的所有内容的名字装进String[]
5、File[] listFiles() 将调用者对象表示的文件夹下,每一个文件或者文件夹都单独封装为一个File对象,并且放入File[]
6、getPath() 将File对象表示的路径还原回字符串String
代码示例
import java.io.File;
public class Demo09_GetMethod {
public static void main(String[] args) {
//getAbsolutePath()
File file = new File("E:\\1019Java\\day17");
File[] files = file.listFiles();
for (File f : files) {
//System.out.println(f.getAbsolutePath());
System.out.println(f.getName());
}
/*String[] list = file.list();
for (String name : list) {
System.out.println(name);
}*/
//System.out.println(file.length());
/*File file = new File("b.txt");
System.out.println(file.length());*/
/*System.out.println(file.getAbsolutePath());
File file2 = new File("E:\\1019Java\\day18\\笔记\\Day18笔记.docx");
System.out.println(file2.getName());*/
System.out.println(new File("a.txt").getPath());
}
}
(九)获取功能练习
键盘录入一个字符串,该字符串表示一个文件夹路径,如果不是文件夹则重新录入。
打印当前文件夹下,所有大于20M的后缀名是.mp4的文件的绝对路径
代码示例
import java.io.File;
import java.util.Scanner;
/**
* 键盘录入一个字符串,该字符串表示一个文件夹路径,如果不是文件夹则重新录入。
打印当前文件夹下,所有大于20M的后缀名是.mp4的文件的绝对路径
*
* @author Zihuatanejo
*
*/
public class Demo10_Exercise {
public static void main(String[] args) {
File dir = getDir();
//1.我们目前得到了文件夹的路径,可以将文件夹下所有内容逐个转为file对象,便于后期判断
File[] files = dir.listFiles();
//2.遍历数组获取每一个file对象进行判断
for (File file : files) {
//3.判断当前对象是否为合法的文件
if(file.isFile()) {
//4.获取当前文件的名称
String fileName = file.getName();
//获取文件后缀名
//① 获取后缀名的.出现的索引
int index = fileName.lastIndexOf(".");
//② 截取后缀名
String suffixName = fileName.substring(index);
//5.判断文件是否为.mp4结尾
if(suffixName.equals(".mp4")) {
//6.判断当前.mp4文件大小是否大于20M
if(file.length() / 1024 / 1024 > 100) {
System.out.println(file.getAbsoluteFile());
}
}
}
}
}
/**
* 判断一个字符串路径是否是合法的文件夹路径
*
* @return 表示合法文件夹路径的File对象
*/
public static File getDir() {
Scanner sc = new Scanner(System.in);
System.out.println("请录入一个文件夹的路径:");
while (true) {
String strPath = sc.nextLine();
//1.为了判断字符串是否为合法文件夹路径,要先将字符串路径转为File对象
File path = new File(strPath);
//2.判断当前的File对象表示的路径是否为合法文件夹
if (path.isDirectory()) {
return path;
} else {
System.out.println("请录入合法的文件夹路径:");
}
}
}
}
(十)File和递归的练习
键盘录入一个文件夹路径,删除该文件夹(文件夹是嵌套文件夹)
代码示例
import java.io.File;
//键盘录入一个文件夹路径,删除该文件夹(文件夹是嵌套文件夹)
public class Demo11_FileAndRecursionExercise {
public static void main(String[] args) {
//得到文件夹路径
File dir = Demo10_Exercise.getDir();
delDir(dir);
}
public static void delDir(File dir) {
//1.打开文件夹
File[] files = dir.listFiles();
//2.获取文件夹中的每一个内容
for (File file : files) {
//3.判断每一个内容,如果是文件就直接删除
if(file.isFile()) {
file.delete();
} else {
delDir(file);
}
}
//5.删除文件夹
dir.delete();
}
}