一、复习
1、枚举(JDK1.5 引入的)
枚举是一种特殊的类型,它的对象是固定,有限的几个常量对象。在枚举类的外面只能通过 “枚举类名.常量对象名” 的方式来选一个对象,而不是像普通类一样直接 new。
语法格式:
【修饰符】 enum 枚举类名{
常量对象名, 常量对象名, 常量对象名; //常量对象必须在第一个语句列出来
【修饰符】 final 数据类型 变量名; //final是建议加。如果加了final,无参构造要么没有,要么在无参构造中必须显式的给它赋值。
//private通常省略,因为枚举类的构造器一定是private
private 枚举类名(){
}
private 枚举类名(形参列表){
}
//....
}
- 枚举类的直接父类固定是 java.lang.Enum
- 枚举类没有子类,因为它的构造器私有化,子类无法调用
- switch-case 从 JDK1.5 开始,支持枚举类型
枚举类的一些方法:
- String
name()
:获取枚举常量对象名 - int
ordinal()
:获取枚举常量对象的下标 - static 枚举类型[]
values()
:得到所有的枚举常量对象 - static 枚举类型
valueOf("常量对象名")
:根据名称获取具体的枚举常量对象 - Enum 类的 toString 方法已经重写过了,默认返回的是枚举常量对象名
2、密封类
语法格式:
【其他修饰符】 sealed class 密封类名 permits 子类们{
}
密封类的子类是受限制的,只能是 permits 后面列出来的类,才有资格直接继承密封类。子类如果继承了密封类,那么子类必须是 3 种情况之一:
- 继续密封 sealed
- 直接终止 final
- 恢复普通 non-sealed
3、记录类
语法格式:
【修饰符】 record 记录类名(数据类型 实例变量名, 数据类型 实例变量名){
}
- 记录类的实例变量只能在 记录类名后面的()中声明,它们都是 final 的
- 记录类会自动生成 get 方法、toString 方法、hashCode 和 equals 方法。所有实例变量没有 set 方法。
- 记录类的构造器就这一个全参构造
- 关于静态变量等成员正常声明即可
4、JUnit5 的注解
- @Test:标记在单元测试方法上,可以作为 Java 测试程序入口。
- 单元测试方法必须是非 private、void、()、非 staic,所在的类只有 1 个非 private 的无参构造器
- @BeforeEach:它标记的方法会在每一个@Test 方法执行之前运行
- @AfterEach:它标记的方法会在每一个@Test 方法执行之后运行
- @BeforeEach、@AfterEach 标记的方法也是非 static
- @BeforeAll:它标记的方法会所有@BeforeEach、@Test、@AfterEach 的方法之前运行,且只运行 1 次
- @AfterAll:它标记的方法会所有@BeforeEach、@Test、@AfterEach 的方法之后运行,且只运行 1 次
- @BeforeAll 和@AfterAll 标记的方法必须是 static
5、lombok
- @Data:根据本类声明的实例变量列表来生成 getter/setter、toString 方法、hashCode 和 equals 方法
- @NoArgsConstructor:无参构造
- @AllArgsConstructor:全参构造
- @RequiredArgsConstructor:为@NonNull 标记的实例变量初始化,它的参数是@NotNull 标记的实例变量
- @NonNull:标记在实例变量上面,表示这个属性是必填项
- @ToString:单独生成 toString 方法,如果要内部调用
super.toString()
,需要@ToString(callSuper=true)
,同理 hashCode 和 equals 方法也是一样的 - @Builder:它标记的类需要用建造者模式来创建对象
- 类名.
builder()
.本类属性名(属性名).本类属性名(属性值).build()
- 类名.
- @SuperBuilder:它标记的父类和子类也是用建造者模式来创建对象
- 子类名.
builder()
.父属性名(属性名).子属性名(属性值).build()
- 子类名.
6、核心类库中的基础注解
- @Override:用于标记重写的方法
- @Deprecated:标记已过时的 xx
- @SuppressWarnings:用于抑制警告
- @FunctinalInterface:用于标记某个接口有且只有 1 个抽象需要被重写
7、数学计算的类型
Math 类:都是静态方法
- abs 方法:求绝对值
- pow 方法:求幂次方
- sqrt 方法:求平方根
- ceil:向上取整
- floor:向下取整
- round:四舍五入,近似值
- random:产生[0,1)的随机值
- max:求最大值
- min:求最小值
- PI:圆周率
- .......
Random 类:都是非静态方法
nextDouble:产生[0,1)的随机值
nextInt
- nextInt():产生一个 int 范围的任意值
- nextInt(边界):产生[0, 边界)的 int 值
- nextInt(边界 1,边界 2):产生[边界 1, 边界 2)的 int 值
nextBoolean:产生 true 或 false
......
BigInteger、BigDecimal:任意大小和精度的整数和小数
- 通过对象调用 add、subtract、mutiply、divide 等方法完成计算
二、包装类
2.1 为什么要有包装类
Java 是面向对象的语言,但是它里面延续了 C 语言的 8 种基本数据类型,它们不是对象。Java 绝大部分都是面向对象,很多语法、新特性、API 都是为对象设计的,那么 8 种基本数据类型就与它们不兼容,格格不入。8 种基本数据类型有自己的优点:简洁、明了、有丰富的运算符支持。Java 为了既能保留 8 种基本数据类型的优势,又能与对象“兼容”,所以为这 8 种基本数据类型设计了对应的包装类,可以实现基本数据类型与对象之间自由切换。
2.2 包装类型有哪些
基本数据类型 | 包装类(类名首字母大写) |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
2.3 装箱与拆箱
装箱:把基本数据类型转为包装类的对象
拆箱:把包装类的对象转为基本数据类型的值
JDK5 之后,装箱和拆箱可以自动完成,称为自动装箱、自动拆箱,使得整个过程是无感的。
@Test
public void test1(){
//自动装箱与拆箱
Integer i = 1;//自动装箱。 左边是Integer(引用数据类型),右边的1是int(基本数据类型)
Integer j = new Integer(2);//明显是对象
int b = j;//自动拆箱。 左边是int(基本数据类型),右边j是Integer类型的对象(引用数据类型)
System.out.println("i = " + i);
System.out.println("b = " + b);
}
2.4 包装类有一些常用的方法
1、将字符串转为基本数据类型的值
- 包装类名.parseXxx
@Test
public void test2(){
String str1 = "123";
// int num = str1;//错误。 类型完全不兼容
int num = Integer.parseInt(str1);
System.out.println(num + 1);//124
String str2 = "3.14";
double pi = Double.parseDouble(str2);
System.out.println(pi + 1);
String str3 = "true";
boolean b = Boolean.parseBoolean(str3);
if(b){
System.out.println("条件成立");
}
String str4 = "hello";
int i = Integer.parseInt(str4);//java.lang.NumberFormatException
System.out.println("i = " + i);
}
2、获取每种类型的最大值、最小值
- 包装类.MAX_VALUE
- 包装类.MIN_VALUE
@Test
public void test3(){
System.out.println("int最大值:" + Integer.MAX_VALUE);
System.out.println("int最小值:" + Integer.MIN_VALUE);
System.out.println("long最大值:" + Long.MAX_VALUE);
System.out.println("long最小值:" + Long.MIN_VALUE);
}
3、比较两个数据值的大小
- 包装类名.
compare(值1,值2)
:当值 1>值 2 时,返回正整数;当值 1<值 2,返回负整数;当值 1=值 2,返回 0.
@Test
public void test4(){
double a = 5.3;
double b = 4.6;
//要求比较a,b的大小,且当a>b,结果是整整数,a<b,结果是负整数,a=b,结果是0
/* int result;
if(a>b){
result = 1;
}else if(a<b){
result= -1;
}else{
result = 0;
}
System.out.println("result = " + result);*/
int result = Double.compare(a,b);
System.out.println("result = " + result);
}
@Test
public void test5(){
char c1 = '尚';
char c2 = '硅';
int result = Character.compare(c1,c2);
System.out.println("result = " + result);
}
2.5 包装类的一些特点
1、包装类对象不可变
package com.atguigu.wrapper;
import org.junit.jupiter.api.Test;
public class TestWrapper2 {
@Test
public void test1(){
int a = 1;
Integer b = 1;
int[] c = {1};
change(a,b,c);
System.out.println("a = " + a);//1
System.out.println("b = " + b);//1
System.out.println("c[0] = " + c[0]);//2
}
/*
int a是基本数据类型,实参给形参的是数据值副本,形参修改与实参无关。
Integer b是引用数据类型,实参给形参的是地址值的副本。但是因为包装类对象不可变。
一旦要修改包装类对象的值,那么就会得到新对象
int[] c也是引用数据类型,实参给形参的是地址值的副本。形参数组修改了元素,等级于实参数组修改了元素。
如果形参数组指向1个新数组,那么新数组的元素修改与实参无关。
*/
public void change(int a, Integer b, int[] c){
a++;
b++; // b = new Integer(b+1)
// c = new int[5];
c[0]++;
}
}
2、部分包装类对象可以被共享
正因为包装类对象不可变,所以包装类对象可以被安全的共享。如果要被共享,这些对象会被缓存起来。
因为不是所有包装类对象都是很常用的,如果把所有 包装类的对象都缓存起来,内存压力太大了,所以它只缓存部分常用的对象。
包装类 | 数据范围 | 缓存对象范围 |
---|---|---|
Byte | [-128, 127] | [-128, 127] |
Short | [-32768, 32767] | [-128, 127] |
Integer | [Integer.MIN_VALUE, Integer.MAX_VALUE] | [-128, 127] |
Long | [Long.MIN_VALUE, Long.MAX_VALUE] | [-128, 127] |
Float | [Float.MIN_VALUE, Float.MAX_VALUE] | 无 |
Double | [Double.MIN_VALUE, Double.MAX_VALUE] | 无 |
Character | [0, 65535] | [0,127] |
Boolean | true,false | true,false |
package com.atguigu.wrapper;
import org.junit.jupiter.api.Test;
public class TestWrapper3 {
@Test
public void test1(){
int a = 1;
int b = 1;
System.out.println(a == b);//true 比较数据值
Integer i = 1;
Integer j = 1;
System.out.println(i == j);//true 比较地址值
//1在Integer的缓存对象范围内,i和j指向同一个对象
}
@Test
public void test2(){
int a = 200;
int b = 200;
System.out.println(a == b);//true 比较数据值
Integer i = 200;
Integer j = 200;
System.out.println(i == j);//false 比较地址值
//200不在Integer的缓存对象范围内,i和j指向不同对象
}
@Test
public void test3(){
int a = 1;
int b = 1;
System.out.println(a == b);//true 比较数据值
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//false 比较地址值
//这里明确用new,不用缓存对象
//只有自动装箱 或 包装类.valueOf方法得到包装类的对象,才会用缓存对象
}
@Test
public void test4(){
int a = 1;
int b = 1;
System.out.println(a == b);//true 比较数据值
Integer i = Integer.valueOf(1);
Integer j = Integer.valueOf(1);
System.out.println(i == j);//true 比较地址值
//这里明确用new,不用缓存对象
//只有自动装箱 或 包装类.valueOf方法得到包装类的对象,才会用缓存对象
}
}
3、包装类对象除了一种情况计算,其余都拆箱计算
- 只有== 或 != 的左右两边都是包装类对象,不会拆箱的
- 其他计算都拆箱
package com.atguigu.wrapper;
import org.junit.jupiter.api.Test;
public class TestWrapper4 {
@Test
public void test1(){
Integer i = 200;
Integer j = 200;
System.out.println(i == j);//比较地址值
//当== 或 != 的左右两边都是包装类对象,不会拆箱的
Double d = 1.0;
// System.out.println(i == d);//报错。 比较地址值 Java中两种不同类型且不是父子类关系的对象是不能比较地址
}
@Test
public void test2(){
Integer i = 200;
Integer j = 250;
System.out.println(i + j);//拆箱计算
System.out.println(i > j);//拆箱比较
Double d = 230.0;
System.out.println(i + d);//拆箱计算
System.out.println(i > d);//拆箱比较
}
@Test
public void test3(){
Integer i = 200;
double d = 200.0;
System.out.println(i==d);//拆箱比较
//==左边不全是包装类
}
}
2.6 类型转换问题特别说明
package com.atguigu.wrapper;
import org.junit.jupiter.api.Test;
public class TestWrapper5 {
@Test
public void test1(){
int a = 1;
Integer b = a;
int[] arr = {1};
//Integer[] nums = arr;//错误
//int <-> Integer可以自动装箱与拆箱
//int[] <-> Integer不可以 自动装箱与拆箱,也不可以自由转换
}
@Test
public void test2(){
//关于自动装箱与拆箱,只能 基本数据类型 与 自己对应的包装类之间自动装箱与拆箱
Integer i = 1;
Double b = 1.0;
// Double d = 1;//错误 ,右边1是int,与Double不是对应的包装类
Double d = 1D;//数字中D结尾代表是double类型。F结尾代表float类型。L结尾代表long类型。
}
}
三、比较器
3.1 自然比较接口:Comparable(优先)
Java 中对象是不能直接用>,<等运算符比较大小的,那么两个对象比较大小通常需要调用方法来比较大小。因为担心各自取的方法名不一致,为了统一标准,Java 规定凡是对象要比较大小,那么对象所在的类都要实现 java.lang.Comparable 接口,重写 int compareTo(Object obj)
方法。
核心类库中已经定义好的接口及其抽象方法:
public interface Comparable<T> { //今天先忽略<T>,这个等泛型部分讲解
public abstract int compareTo(T o);
}
案例 1
package com.atguigu.compare;
import lombok.*;
@Data
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
public class Student implements Comparable{
@NonNull
private String name;
@NonNull
private int score;
@NonNull
private double weight;
private int height;
//在compareTo方法中要说明如果比较两个学生对象的大小
@Override
public int compareTo(Object obj) {
//例如:我们这里想要按照成绩比较大小
//当我们在测试类中 s1.compareTo(s2)
//比较this和obj对象,this就是s1, obj就是 s2
//因为compareTo方法的形参是Object类型,所以实参s2就发生了向上转型,obj就失去了调用score等成员的能力
//所以要向下转型
Student other = (Student) obj;//向下转型
return this.score - other.score;
}
}
@Test
public void test1(){
Student s1 = new Student("张三",86,120);
Student s2 = new Student("李四",96,110);
// System.out.println(s1 > s2);//错误
int result = s1.compareTo(s2);
System.out.println("result = " + result);//返回值是负数,代表s1<s2
}
案例 2
package com.atguigu.compare;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Circle implements Comparable{
private double radius;
@Override
public int compareTo(Object o) {
//这里比较两个圆对象的半径大小
/*if(this.radius>((Circle)o).radius){
return 1;
}else if(this.radius>((Circle)o).radius){
return -1;
}else{
return 0;
}*/
return Double.compare(this.radius, ((Circle)o).radius);
}
}
@Test
public void test2(){
Circle c1 = new Circle(2.6);
Circle c2 = new Circle(2.5);
int result = c1.compareTo(c2);
System.out.println("result = " + result);
//返回值是正数,代表c1>c2
}
3.2 定制比较接口:Comparator(备胎)
如果 Comparable 接口不能满足我们的新需求,就需要找 java.util.Comparator 接口:
@FunctionalInterface
public interface Comparator<T> {//今天先忽略<T>,这个等泛型部分讲解
int compare(T o1, T o2);
}
案例 1
package com.atguigu.compare;
import java.util.Comparator;
public class WeightComparator implements Comparator {
//我想用它来比较两个Student对象的体重大小
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return Double.compare(s1.getWeight(), s2.getWeight());
}
}
@Test
public void test1(){
Student s1 = new Student("张三",86,120);
Student s2 = new Student("李四",96,110);
//希望这里按照体重比较大小
WeightComparator weightComparator = new WeightComparator();
int result = weightComparator.compare(s1, s2);
System.out.println("result = " + result);
//结果是正数,代表s1>s2
}
@Test
public void test1_2(){
Student s1 = new Student("张三",86,120);
Student s2 = new Student("李四",96,110);
//希望这里按照体重比较大小
// WeightComparator weightComparator = new WeightComparator();
Comparator weightComparator = new Comparator(){
//我想用它来比较两个Student对象的体重大小
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return Double.compare(s1.getWeight(), s2.getWeight());
}
};
int result = weightComparator.compare(s1, s2);
System.out.println("result = " + result);
//结果是正数,代表s1>s2
}
案例 2
package com.atguigu.compare;
import java.util.Comparator;
public class HeightComparator implements Comparator {
//我想用它来比较两个Student对象的身高
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return Integer.compare(s1.getHeight(), s2.getHeight());
}
}
@Test
public void test2(){
Student s1 = new Student("张三",86,120,178);
Student s2 = new Student("李四",96,110,180);
//希望这里按照身高比较大小
HeightComparator heightComparator = new HeightComparator();
int result = heightComparator.compare(s1, s2);
System.out.println("result = " + result);
//结果是负数,代表s1<s2
}
@Test
public void test2_2(){
Student s1 = new Student("张三",86,120,178);
Student s2 = new Student("李四",96,110,180);
//希望这里按照身高比较大小
// HeightComparator heightComparator = new HeightComparator();
Comparator heightComparator = new Comparator(){
//我想用它来比较两个Student对象的身高
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return Integer.compare(s1.getHeight(), s2.getHeight());
}
};
int result = heightComparator.compare(s1, s2);
System.out.println("result = " + result);
//结果是负数,代表s1<s2
}
3.3 对比
例如:学生 Student 要比较大小
Comparable | Comparator | |
---|---|---|
英语词性 | 形容词 | 名词 |
谁来实现它 | 要比较大小的对象的类型,那么就是 Student 类实现 Comparable,代表学生对象本身具备可比较大小的功能,compareTo 方法。 | 单独有一个类(有名字的类,也可以是匿名的类)来实现这个接口。这个类的对象用于比较两个对象对象的大小。例如:WeightComparator 类或 HeightComparator 类 |
比较方式 | 学生对象.compareTo(另一个学生对象) | (1)先创建 HeightComparator 或 WeightComparator 的对象,例如对象名是 c (2) c.compare(学生对象1,学生对象2) |
此时 c 相当于是裁判的角色 |
2.4 进一步的应用
2.4.1 模仿 Arrays 定义一个数组工具类 MyArrays
package com.atguigu.compare;
import java.util.Comparator;
public class MyArrays {
//可以为所有对象数组排序(例如:冒泡排序)
public static void sort(Object[] arr){
for(int i=1; i<arr.length; i++){
for(int j=1; j<=arr.length-i; j++){
//arr[j-1] 与 arr[j] 比较
// (Comparable)arr[j-1] //把arr[j-1]元素转为 Comparable
//因为只有这个类型的实现类对象,才有 compareTo方法
// ((Comparable)arr[j-1]) 这里加()是因为要先转型,再. 方法
if(((Comparable)arr[j-1]).compareTo(arr[j])>0){
Object temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}
}
}
}
public static void sort(Object[] arr, Comparator c){
for(int i=1; i<arr.length; i++){
for(int j=1; j<=arr.length-i; j++){
//arr[j-1] 与 arr[j] 比较
if(c.compare(arr[j-1], arr[j]) > 0){
Object temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}
}
}
}
/* //可以为所有对象数组排序(例如:冒泡排序)
public static void sort(Object[] arr){
for(int i=1; i<arr.length; i++){
for(int j=1; j<arr.length-i; j++){
//arr[j-1] 与 arr[j] 比较
if(arr[j-1] > arr[j]){ //对象不能用>,<运算符直接比较大小
Object temp = arr[j-1];
arr[j-1] = arr[j];
arr[j] = temp;
}
}
}
}*/
}
测试类
package com.atguigu.compare;
import org.junit.jupiter.api.Test;
public class TestMyArrays1 {
@Test
public void test1(){
Student[] arr = new Student[3];
arr[0] = new Student("张三",89,120,180);
arr[1] = new Student("李四",96,150,150);
arr[2] = new Student("王五",85,170,170);
System.out.println("排序之前:");
for (Student student : arr) {
System.out.println(student);
}
//排序
MyArrays.sort(arr);
System.out.println("按照成绩升序排序之后:");
for (Student student : arr) {
System.out.println(student);
}
System.out.println("按照体重升序排序之后:");
WeightComparator weightComparator = new WeightComparator();
MyArrays.sort(arr, weightComparator);
for (Student student : arr) {
System.out.println(student);
}
System.out.println("按照身高升序排序之后:");
HeightComparator heightComparator = new HeightComparator();
MyArrays.sort(arr, heightComparator);
for (Student student : arr) {
System.out.println(student);
}
}
}
2.4.2 直接使用 Arrays 工具类
package com.atguigu.compare;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
public class TestArrays {
@Test
public void test1(){
Student[] arr = new Student[3];
arr[0] = new Student("张三",89,120,180);
arr[1] = new Student("李四",96,150,150);
arr[2] = new Student("王五",85,170,170);
System.out.println("排序之前:");
for (Student student : arr) {
System.out.println(student);
}
//排序
Arrays.sort(arr);
System.out.println("按照成绩升序排序之后:");
for (Student student : arr) {
System.out.println(student);
}
System.out.println("按照体重升序排序之后:");
WeightComparator weightComparator = new WeightComparator();
Arrays.sort(arr, weightComparator);
for (Student student : arr) {
System.out.println(student);
}
System.out.println("按照身高升序排序之后:");
HeightComparator heightComparator = new HeightComparator();
Arrays.sort(arr, heightComparator);
for (Student student : arr) {
System.out.println(student);
}
}
}
package com.atguigu.compare;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Comparator;
public class TestArrays2 {
@Test
public void test1(){
Student[] arr = new Student[3];
arr[0] = new Student("张三",89,120,180);
arr[1] = new Student("李四",96,150,150);
arr[2] = new Student("王五",85,170,170);
System.out.println("排序之前:");
for (Student student : arr) {
System.out.println(student);
}
//排序
Arrays.sort(arr);
System.out.println("按照成绩升序排序之后:");
for (Student student : arr) {
System.out.println(student);
}
System.out.println("按照体重升序排序之后:");
// WeightComparator weightComparator = new WeightComparator();
Comparator weightComparator = new Comparator(){
//我想用它来比较两个Student对象的体重大小
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return Double.compare(s1.getWeight(), s2.getWeight());
}
};
Arrays.sort(arr, weightComparator);
for (Student student : arr) {
System.out.println(student);
}
System.out.println("按照身高升序排序之后:");
// HeightComparator heightComparator = new HeightComparator();
Comparator heightComparator = new Comparator(){
//我想用它来比较两个Student对象的身高
@Override
public int compare(Object o1, Object o2) {
Student s1 = (Student) o1;
Student s2 = (Student) o2;
return Integer.compare(s1.getHeight(), s2.getHeight());
}
};
Arrays.sort(arr, heightComparator);
for (Student student : arr) {
System.out.println(student);
}
}
}
四、IO 流
4.1 File 类
File 是文件或文件夹(或目录)的抽象表现形式。每一个 File 的对象代表一个文件或文件夹。这个文件或文件夹可能是在硬盘中存在的,也可能是不存在。
4.1.1 File 类的操作方法系列 1:获取各种属性
length()
:获取文件大小isFile()
是文件吗isDirectory()
:是文件夹吗isHidden()
:是隐藏的吗exists()
:存在吗lastModified()
:最后修改时间getName()
:获取文件或文件夹的名称getPath()
:获取文件或文件夹的路径
4.1.2 文件或文件夹的路径问题:
package com.atguigu.file;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.io.IOException;
public class TestPath {
@Test
public void test1(){
/*
斜杆的方向: 路径分隔符
(1)\ 早期windows只支持这种,现在windows两种都支持,默认或习惯仍然是 \
因为Java中\有特殊意义的,代表转义。所以当你要表示普通的\的时候,需要\\进行转义
(2)/ 其他平台包含网址 都习惯用 /
*/
File f = new File("D:\\atguigu\\javaee\\Java0625\\note");
}
@Test
public void test2() throws IOException {//不处理,直接扔出去,谁爱处理谁处理
/*
(1)绝对路径:
在windows操作系统下,以盘符开头的,例如:D:\atguigu\javaee\Java0625\note
在其他操作系统下,以 / 开头的,就是绝对路径
(2)相对路径
在windows操作系统下,不是以盘符开头的,例如: javaee\\1.txt
在其他操作系统下,不是以 / 开头的
相对谁?
凡是相对都得参照物。
如果以 @Test标记的单元测试方法为入口的, 那么它相对路径是相对与当前的module
如果以main为入口的,那么它相对路径是相对project
*/
File file = new File("1.txt");
file.createNewFile();
}
public static void main(String[] args) throws IOException {
File file = new File("2.txt");
file.createNewFile();
}
@Test
public void test3()throws IOException{
File file = new File("../../1.txt");
System.out.println("构造路径:" + file.getPath());//路径:..\..\1.txt
System.out.println("绝对路径:" + file.getAbsolutePath());
System.out.println("规范绝对路径:" + file.getCanonicalPath());
}
}
4.1.3 File 类的操做方法系列 2
操作文件或文件夹(创建、删除、重命名)
createNewFile()
:创建新文件mkdir()
:创建文件夹mkdirs()
:创建多级文件夹delete()
:删除文件或空文件夹renameTo(新名字的File对象)
:重命名文件或文件夹
4.1.4 File 类的操作方法系列 3
获取上级目录或下级文件或目录
getParent()
getParentFile()
list()
listFiles()
package com.atguigu.file;
import org.junit.jupiter.api.Test;
import java.io.File;
public class TestFile3 {
@Test
public void test1(){
File f = new File("D:\\temp\\img\\dog.jpg");
String parent = f.getParent();
System.out.println("parent = " + parent);
//parent = D:\temp\img
File parentFile = f.getParentFile();
System.out.println("parentFile = " + parentFile);
//parentFile = D:\temp\img
}
@Test
public void test2(){
//如果要获取下一级,首先File对象得是一个文件夹的File对象,否则没有下一级
/*File f = new File("D:\\temp\\img\\dog.jpg");
File[] files = f.listFiles();
for (File sub : files) {
System.out.println(sub);
}*///错误,因为文件没有下一级
File f = new File("D:\\temp\\img");
File[] files = f.listFiles();
for (File sub : files) {
System.out.println(sub);
}
}
@Test
public void test3(){
File f = new File("d:\\temp");
//看它的下一级,如果下一级是文件夹,继续看下一级
listAllSubs(f);
}
public void listAllSubs(File f){
if(f.isDirectory()){
//继续看下一级
File[] files = f.listFiles();
for (File sub : files) {
listAllSubs(sub);//自己调用自己(递归)
}
}else if(f.isFile()){
System.out.println(f);
}
}
@Test
public void test4(){
//删除非空文件夹
File f = new File("d:\\尚硅谷2");//找一个没用的文件夹测试
forceDelete(f);
}
public void forceDelete(File f){
if(f.isDirectory()){
//把文件夹的下一级先删除
File[] files = f.listFiles();
for (File sub : files) {
forceDelete(sub);//递归,自己调用自己
}
}
f.delete();//如果是文件或已经清空下一级的空文件夹,可以通过它删除
}
@Test
public void test5(){
File f = new File("d:\\temp");
//System.out.println("文件夹大小:" + f.length());//文件夹大小:8192(错误)
//无法直接获取文件夹的大小
System.out.println("文件夹大小:" + getTotalLength(f));
}
public long getTotalLength(File f){
if(f.isFile()){
return f.length();
}else if(f.isDirectory()){
//累加这个文件夹下的所有下一级文件或文件夹的总大小
long sum = 0;
File[] files = f.listFiles();
for (File sub : files) {
//sum += sub的大小;
sum += getTotalLength(sub);//递归
}
return sum;
}
return 0;
}
}
4.1.5 Hutool 工具
package com.atguigu.file;
import cn.hutool.core.io.FileUtil;
import org.junit.jupiter.api.Test;
import java.io.File;
public class TestHutool {
@Test
public void test1(){
File f = new File("d:\\shangguigu2");
FileUtil.del(f);//可以直接删除非空文件夹
}
@Test
public void test2(){
File f = new File("d:\\temp");
long size = FileUtil.size(f);
System.out.println("size = " + size);//size = 725382355
}
}
4.2 IO 流类
IO 流的作用是用于读或写数据。
- 读可以从文件读、从网络通道中读、从内存读取...
- 写也可以把数据写到文件中、发送到网络通道中、写到内存中...
今天主要围绕文件的读和写。
4.2.1 文件 IO 流
文件 IO 流一共有 4 个:
- FileInputStream:从文件读。文件字节输入流
- FileOutputStream:把数据写到文件。文件字节输出流。
- FileReader:从文件读。文件字符输入流。
- FileWrtier:把数据写到文件。文件字符输出流。
分类方式之一:输入流和输出流
分类方式之二:字节流和字符流
- 字节流:以字节为单位。一次最少可以读取 1 个字节。1 个字节可能不是一个完整的字符。
- 如果是非纯文本文件,那么只能使用字节流。
- 当然纯文本文件也可以用字节流。
- 字符流:以字符为单位。一次最少必须读取 1 个字符。1 个字符可能是 1-4 个字节。
- 如果文件是纯文本文件,建议用字符流。
案例 1:把单词写到纯文本文件中
package com.atguigu.io;
import org.junit.jupiter.api.Test;
import java.io.FileWriter;
import java.io.IOException;
public class TestFileWriter {
@Test
public void test1() throws IOException {
FileWriter fw = new FileWriter("d:\\1.txt");//覆盖模式
fw.write("hello");
fw.write("java");
fw.flush();
fw.write("world");
fw.write("chai");
fw.close();
/*
如果IO流要结束了,那么用close()
如果IO流后面还要用,只是把前面的数据刷出去,用flush()
*/
}
@Test
public void test2() throws IOException {
FileWriter fw = new FileWriter("d:\\1.txt", true);//追加模式
fw.write("尚硅谷");
fw.write("最最棒");
fw.close();
}
@Test
public void test3() throws IOException {
FileWriter fw = new FileWriter("d:\\2.txt");//覆盖模式
//如果2.txt不存在,会自动创建。如果存在,现在是覆盖或追加。
fw.write("hello");
fw.write("java");
fw.close();
}
@Test
public void test4() throws IOException {
FileWriter fw = new FileWriter("d:\\尚硅谷\\2.txt");//覆盖模式
//如果文件夹不存在,不会自动创建,报错
//java.io.FileNotFoundException: d:\尚硅谷\2.txt (系统找不到指定的路径。)
fw.write("hello");
fw.write("java");
fw.close();
}
}
案例 2:读取纯文本文件
package com.atguigu.io;
import org.junit.jupiter.api.Test;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
public class TestFileReader {
@Test
public void test() throws IOException {
FileReader fr = new FileReader("d:\\1.txt");
//以字符为单位读取
System.out.println(fr.read());//97 a
System.out.println(fr.read());//98 b
System.out.println(fr.read());//99 c
System.out.println(fr.read());//23578 尚
fr.close();
/*
int read():一次读1个字符,返回它的编码值(Unicode编码值)
*/
}
@Test
public void test2() throws IOException {
FileReader fr = new FileReader("d:\\1.txt");
char[] arr = new char[5];//数组长度为5。最多一次能读取5个字符
while(true){
int len = fr.read(arr);
if(len == -1){
break;
}
System.out.println(len);
System.out.println(Arrays.toString(arr));
}
/*
文件共9个字符
3次,第1次是5个,第1次是4个,第3次是返回-1
*/
}
@Test
public void test3() throws IOException {
FileReader fr = new FileReader("d:\\1.txt");
char[] arr = new char[5];//数组长度为5。最多一次能读取5个字符
while(true){
int len = fr.read(arr);
if(len == -1){
break;
}
// System.out.println(Arrays.toString(arr));
System.out.print(new String(arr,0,len));
/*
new String(arr,0,len) 把arr数组中len个字符取出来构建一个字符串
*/
}
/*
文件共9个字符
3次,
第1次是5个,[a, b, c, 尚, h]
第1次是4个,[e, l, l, o, h]
第3次是返回-1
*/
}
@Test
public void test4() throws IOException {
FileReader fr = new FileReader("d:\\3.txt");
//如果读的时候文件不存在,会报错java.io.FileNotFoundException: d:\3.txt (系统找不到指定的文件。)
System.out.println(fr.read());
fr.close();
}
}
案例 3:字节流复制文件
package com.atguigu.io;
import org.junit.jupiter.api.Test;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class TestCopy {
@Test
public void test1() throws IOException {
// copy("d:\\temp\\img\\dog.jpg", "d:\\狗.jpg");
// copy("d:\\1.txt","d:\\3.txt");
copy("E:\\software\\jdk\\jdk-17_windows-x64_bin.exe","d:\\jdk-17_windows-x64_bin.exe");
}
/**
* 这是一个复制文件的方法。例如:d:\temp\img\dog.jpg文件复制到 d:\狗.jpg。
* @param srcFile String 原文件的完整路径名
* @param destFile String 目标文件的完整路径名
*/
public void copy(String srcFile, String destFile) throws IOException {
FileInputStream fis = new FileInputStream(srcFile);
FileOutputStream fos = new FileOutputStream(destFile);
byte[] arr = new byte[1024*1024];//字节的长度,决定一次转运的字节数量
while(true){
int len = fis.read(arr);//装车过程,并返回装了几个字节
if(len == -1){
break;
}
fos.write(arr, 0, len);//这次装车多少,就运送多少
}
fis.close();
fos.close();
}
}