1. Object 类

理论上 Object 类是所有类的父类,即直接或间接地继承 java.lang.Object 类。

由于所有的类都继承 Object 类,因此省略了 extends Object 关键字。

Object 类中主要有以下方法:

  • toString()
  • getClass()
  • equals()
  • clone()
  • finalize()
1.1 clone() 方法

在 Java 语言中, clone() 方法被对象调用,用来复制对象。

所谓的复制对象,即分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象。

在 Java 语言中,有以下两种方式创建对象:

  • 使用 new 操作符创建一个对象

    new 操作符的本意是分配内存。

    1. 程序执行到 new 操作符时, 首先去看 new 操作符后面的类型,需要分配多大的内存空间;
    2. 分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化;
    3. 构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。
  • 使用 clone() 方法复制一个对象

    clone() 方法第一步与 new 类似,都是分配内存。

    1. 调用clone方法时,分配的内存和源对象(即调用clone方法的对象)相同;

    2. 然后再使用源对象中对应的各个域,填充新对象的域;

    3. 填充完成之后,clone() 方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。

clonecopy 的区别:

  • copy 只是简单复制了引用,两个对象都是指向内存同一个
  • clone 会生成一个新的对象,并且与源对象具有相同的属性值和方法

深拷贝浅拷贝

Object 在对某个对象实施 Clone 时对其是一无所知的,它仅仅是简单地执行域对域的 copy,这就是浅拷贝

  • 克隆类和原始类可能会共享一部分信息(原始类存在引用类型的变量)

重写 clone() 方法,实现深拷贝,代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Person implements Cloneable {

private int age ;
private String name;

public Person(int age, String name) {
this.age = age;
this.name = name;
}

public Person() {}

public int getAge() {
return age;
}

public String getName() {
return name;
}

@Override
protected Object clone() throws CloneNotSupportedException {
Person person = (Person)super.clone();
return person;
}
}

注意事项:

  • 使用 clone() 方法必须实现接口 Cloneable,默认实现的就是浅拷贝(引用拷贝)
  • 如果想要深拷贝一个对象,这个对象必须要实现 Cloneable 接口,重写 clone() 方法,并且在 clone() 方法内部,把该对象引用的其他对象也要 clone 一份 , 这就要求这个被引用的对象必须也要实现 Cloneable 接口并且实现 clone() 方法。
  • 如果在拷贝一个对象时,要想让这个拷贝的对象和源对象完全彼此独立,那么在引用链上的每一级对象都要被显式的拷贝。
  • String 存在于堆内存、常量池;这种比较特殊, 本身没有实现 Cloneable,传递是引用地址;由本身的 final 性, 每次赋值都是一个新的引用地址,原对象的引用和副本的引用互不影响。因此String就和基本数据类型一样,表现出了"深拷贝"特性。
1.2 toString() 方法

POJO 类必须写 toString 方法。

1.3 getClass() 方法

返回对象的类。

1.4 finalize() 方法

用于实例被垃圾回收器回收时的触发的操作。

当 GC (垃圾回收器) 确定不存在对该对象的有更多引用时,对象的垃圾回收器就会调用这个方法。

工作原理:

一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其 finalize() 方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

1.5 equals() 方法

用于比较两个对象是否相等。

equals() 方法比较两个对象,是判断两个对象引用指向的是同一个对象,即它只是检查两个对象是否指向内存中的同一个地址。

Object 类的 equals() 源码:

1
2
3
public boolean equals(Object obj) {
return (this == obj);
}

如果希望不同内存但相同内容的两个对象使用 equals() 时返回 true,则需要重写父类的 equal()。String 类已经重写了 Object 类中的 equals(),比较内容是否相等。

String 类的 equals() 源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}

==equals() 比较:

  • == 是判断两个对象的内存地址是否相等,即判断是否是同一个对象。
  • equals() 有两种情况:
    1. 第一种情况就是没有被重写的 equals() 方法,它就相当于通过 == 去比较;
    2. 第二种情况是重写了的 equals() 方法,一般重写后都是去比较两个对象的内容(或者说属性)是否相等,具体看重写的方法。
1.6 hashCode() 方法

用于获取对象的 hash 值(是一个整数,表示在哈希表中的位置)

如果两个对象相等,那么它们的 hashCode 值一定要相等

想象一下,假如两个 Java 对象 A 和 B,A 和 B 相等(eqauls() 结果为 true),但 A 和 B 的 hashCode不同,则 A 和 B 存入 HashMap 时的哈希码计算得到的 HashMap 内部数组位置索引可能不同,那么 A 和 B 很有可能允许同时存入 HashMap,显然相等 / 相同的元素是不允许同时存入 HashMap,HashMap 不允许存放重复元素。

不同对象的 hashCode 可能相同

假如两个 Java 对象 A 和 B,A 和 B 不相等(eqauls() 结果为 false),但 A 和 B 的 hashCode 相等,将 A 和 B 都存入 HashMap 时会发生哈希冲突,也就是 A 和 B 存放在 HashMap 内部数组的位置索引相同,这时 HashMap 会在该位置建立一个链接表,将 A 和 B 串起来放在该位置,显然,该情况不违反 HashMap 的使用原则,是允许的。当然,哈希冲突越少越好,尽量采用好的哈希算法以避免哈希冲突。

hashCode 不同的对象一定不相等

如果子类重写了 equals() 方法,就需要重写 hashCode()方法。比如 String 类就重写了 equals() 方法,同时也重写了 hashCode() 方法。

因为当你需要将对象存入到底层为散列表结构的集合中时,是先判断 hashcode 值,碰到相同值时再通过 equals() 进一步判断。hashCode()equals() 两个方法用来协同判断两个对象是否相等的,采用这种方式的原因是可以提高程序插入和查询的速度。如果在重写 equals() 时,不重写 hashCode(),就会导致在某些场景下,例如将两个相等的自定义对象存储在 Set 集合时,如果只重写了 equals 方法,那么默认情况下,Set 进行去重操作时,会先判断两个对象的 hashCode 是否相同,此时因为没有重写 hashCode 方法,所以会直接执行 Object 中的 hashCode 方法,而 Object 中的 hashCode 方法对比的是两个不同引用地址的对象,所以结果是 false,那么 equals 方法就不用执行了,直接返回的结果就是 false:两个对象不是相等的,于是就在 Set 集合中插入了两个相同的对象;但是,如果在重写 equals 方法时,也重写了 hashCode 方法,那么在执行判断时会去执行重写的 hashCode 方法,此时对比的是两个对象的所有属性的 hashCode 是否相同,于是调用 hashCode 返回的结果就是 true,再去调用 equals 方法,发现两个对象确实是相等的,于是就返回 true 了,因此 Set 集合就不会存储两个一模一样的数据了,于是整个程序的执行就正常了。

但这其实是针对当该类会在HashSet, Hashtable, HashMap等等这些本质是散列表的数据结构中用到的时候这种情况。

Java提高篇——equals()与hashCode()方法详解

面试官:重写 equals 时为什么一定要重写 hashCode?


1.7 wait() 方法及其重载
  1. wait() 方法

    让当前线程进入等待状态(直到其它线程调用此对象的 notify() 方法或 notifyAll() 方法)

  2. wait(long timeout) 方法

    让当前线程处于等待(阻塞)状态,直到其他线程调用此对象的 notify() 方法或 notifyAll()方法,或者超过参数 timeout 设置的超时时间。

    • 如果 timeout 参数为 0,则不会超时,会一直进行等待
    • timeout - 等待时间,以毫秒为单位
  3. wait(long timeout, int nanos) 方法

    wait(long timeout) 方法类似,多了一个 nanos 参数,这个参数表示额外时间(以纳秒为单位,范围是 0-999999)

注意事项:

  • 当前线程必须是此对象的监视器所有者,否则会发生 IllegalMonitorStateException 异常。
  • 如果当前线程在等待之前或在等待时被任何线程中断,则会抛出 InterruptedException 异常。
  • 如果传递的参数不合法,则会抛出 IllegalArgumentException 异常。
1.8 notify() 方法

用于唤醒在该对象上等待的某个线程

  • 如果所有的线程都在此对象上等待,那么只会选择一个线程,选择是任意性的,并在对实现做出决定时发生。
  • notify() 方法只能被作为此对象监视器的所有者的线程来调用。

一个线程要想成为对象监视器的所有者,可以使用以下 3 种方法:

  • 执行对象的同步实例方法
  • 使用 synchronized 内置锁
  • 对于 Class 类型的对象,执行同步静态方法

一次只能有一个线程拥有对象的监视器。

一个线程在对象监视器上等待可以调用 wait() 方法。

1.9 notifyAll() 方法

用于唤醒在该对象上等待的所有线程

等待/通知机制,是指线程 A 调用了对象 O 的 wait() 方法进入等待状态,而线程 B 调用了对象 O 的 notify() / notifyAll() 方法,线程 A 收到通知后退出等待队列,进入可运行状态,进而执行后续操作。上述两个线程通过对象O来完成交互,而对象上的 wait() 方法和 notify() / notifyAll() 方法的关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。


2. 包装类

Java 为每种基本数据类型分别设计了对应的类,称之为包装类 (Wrapper Classes)。

基本数据类型 对应的包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
  • 所有的包装类 (Byte, Short, Integer, Long, Float, Double) 都是抽象类 Number 的子类。
  • 每个包装类的对象可以封装一个相应的基本类型的数据,并提供了其它一些有用的方法。
  • 包装类对象一经创建,其内容(所封装的基本类型数据值)不可改变。

基本类型和对应的包装类可以相互装换:

  • 由基本类型向对应的包装类转换称为装箱

    1. 使用 valueOf() 方法将基本类型转换为相应的包装类对象,如:Integer obj = Integer.valueOf(6);
    2. Java 编译器可以直接将基本类型转换为相应的对象(自动装箱),如:Integer obj = 6;
    3. 使用包装类 (Wrapper) 构造函数将基本类型转换为包装对象。(但是在 Java 9 之后,不再使用构造函数)
  • 包装类向对应的基本类型转换称为拆箱

    1. 使用每个包装类中对应的值方法( intValue()doubleValue() 等)

      1
      2
      Integer obj = 6;
      int m = obj.intValue();
    2. Java 编译器可以自动将对象转换为相应的原始类型(自动拆箱)

      1
      2
      Integer obj = 6;
      int m = obj;

特别地,

  1. 将字符串转换为整数

    Integer 类有一个静态的 parseInt() 方法,可以将纯数字字符串转换为整数

    1
    int n = Integer.parseInt(String s, int radix); // s 表示字符串,radix 表示进制,默认为 10
  2. 将整数转化为字符串

    1. toString() 方法,如:String str = Integer.toString(666);
    2. 直接在整数后面加空字符串

基本类型比相应的对象更有效,当需要效率时,总是建议使用基本类型。

3. Math 类

3.1 常量值
  • Math.E

    1
    public static final double E = 2.7182818284590452354;
  • Math.PI

    1
    public static final double PI = 3.14159265358979323846;
3.2 Math.exp() 方法

用于返回自然数底数 e 的参数次方

3.3 Math.pow() 方法

用于返回第一个参数的第二个参数次方

3.4 Math.sqrt() 方法

用于返回参数的算术平方根

3.5 Math.cbrt() 方法

用于返回参数的立方根

3.6 Math.ceil() 方法

对一个数进行上舍入,返回值大于或等于给定的参数,类型为 double 型

  • 个人理解:假设一个坐标轴,给定的参数为上面一点,返回的是给定参数的右边部分的最左端的整数值
3.7 Math.floor() 方法

对一个数进行下舍入,返回值小于或等于给定的参数,类型为 double 型

  • 个人理解:假设一个坐标轴,给定的参数为上面一点,返回的是给定参数的左边部分的最右端的整数值
3.8 Math.rint() 方法

返回最接近参数的整数值(如果有 2 个数同样接近,则会返回偶数的那个)

3.9 Math.round() 方法

“四舍五入”:

  • 参数为正数:小数部分 ≥0.5 时,整数取值向右一个整数,即+1。

  • 参数为负数:小数部分 ≤0.5 时,取值右侧的整数。

注意事项:

  • 参数为 float 型时返回 int 型值
  • 参数为 double 型时返回 long 型值
3.10 Math.random() 方法

用于返回一个随机数,随机数范围为 0.0 =< Math.random < 1.0

4. Random 类

Random 类共有两种构造方法:

  1. Random()

    此构造方法是以系统自身的时间为种子数来构造 Random 对象。

  2. Random(long)

    此构造方法可以自己来选定具体的种子来构造 Random 对象。

虽然 Random 类产生的数字是随机的,但在相同种子数(seed)下的相同次数产生的随机数是相同的(伪随机)。

5. Date 类

封装当前的日期和时间。

Date 类提供两个构造函数来实例化 Date 对象:

  1. Date()

    使用当前日期和时间来初始化对象。

  2. Date(long)

    接收一个参数,该参数是自 1970 年 1 月 1 日 00:00:00 GMT 以来的毫秒。

getTime() 方法

返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

格式化日期

  • 使用 SimpleDateFormat 类

    代码片段示例:

    1
    2
    3
    Date date = new Date();
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    System.out.println("当前时间为: " + ft.format(date));

    SimpleDateFormat 类的 parse() 方法能够按照给定的 SimpleDateFormat 对象的格式化存储来解析字符串

    更多有关 SimpleDateFormat 类内容详见:Java 日期时间 | 菜鸟教程 (runoob.com)

  • 使用 printf() 方法

    使用两个字母格式,以 %t 开头

    更多有关 printf() 方法内容详见:Java 日期时间 | 菜鸟教程 (runoob.com)

sleep() 使当前线程进入停滞状态(阻塞当前线程)

6. Calendar 类

Calendar 类是一个抽象类,在实际使用时实现特定的子类的对象,创建对象的过程对程序员来说是透明的,只需要使用 getInstance() 方法创建即可。

  • 创建一个代表系统当前日期的 Calendar 对象

    1
    Calendar c = Calendar.getInstance();
  • 创建一个指定日期的 Calendar 对象

    1
    2
    3
    4
    5
    Calendar c = Calendar.getInstance();
    c.set(int field, int value); // 第一种
    c.set(int year, int month, int date); // 第二种
    c.set(int year, int month, int date, int hourOfDay, int minute); // 第三种
    c.set(int year, int month, int date, int hourOfDay, int minute, int second); // 第四种

注意事项:

  • Calendar 类的月份是从 0 开始的

    1
    2
    3
    4
    Calendar c = Calendar.getInstance();
    c.set(2024, 2 - 1, 27, 10, 57); // 2 - 1 表示 2 月份
    System.out.println(c.getTime());
    System.out.println(c.get(Calendar.MONTH) + 1); // + 1 还原本来的月份值
  • Calendar 类的 DAY_OF_WEEK 是从星期日开始的

    1
    2
    3
    4
    Calendar c = Calendar.getInstance();
    c.set(2024, 2 - 1, 27, 10, 57);
    System.out.println(c.getTime());
    System.out.println(c.get(Calendar.DAY_OF_WEEK) - 1); // - 1 还原本来的星期值
  • 将日期设为 0 以后,月份将变成了上个月,但月份可以为0

    1
    2
    Calendar c = Calendar.getInstance();
    c.set(2024, 2 - 1, 0); // 结果为 1 月 31 日

常用 Calendar 类对象字段类型

常量 描述
Calendar.YEAR 年份
Calendar.MONTH 月份
Calendar.DATE 日期
Calendar.DAY_OF_MONTH 日期,和 Calendar.DATE 意义完全相同
Calendar.HOUR 12 小时制的小时
Calendar.HOUR_OF_DAY 24 小时制的小时
Calendar.MINUTE 分钟
Calendar.SECOND
Calendar.DAY_OF_WEEK 星期几

Calendar 类的 add(int field, int amount) 方法在可以给定的日历字段中增加或减去指定的时间量

Calendar 的 getInstance() 方法返回一个默认用当前的语言环境和时区初始化的 GregorianCalendar 对象。

  • 特别地,GregorianCalendar 类中含有一个 isLeapYear(int year) 方法,用于确定给定的年份是否为闰年。

7. String 类

String 为字符串常量。即:String 对象创建后是不可以更改的(改变的只是地址,原来的字符串还是存在的,并且产生垃圾)。

举例说明:

1
2
3
4
String str = "Hello ";
str += "World ";
str = str+ "!!!";
System.out.println(str); // 输出结果为:Hello World !!!

String 底层使用一个字符数组来维护,String 类的值是 final 类型的,不能被改变只要一个值改变就会生成一个新的 String 类型对象。

String 类的构造方法详见源码

常量池

  1. Class 常量池

    • Class 常量池在 .class 文件中,用于存放编译器生成的各种字面量(Literal)和符号引用(Symbolic References)
      • 字面量包括:文本字符串、基本数据类型的值、被声明为 final 的常量等;
      • 符号引用包括:类和接口的全限定名、字段名称和描述符、方法名称和描述符。
    • 每个 .class 文件都有一个 Class 常量池

    Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

  2. 运行时常量池

    运行时常量池是 Class 常量池被加载到内存之后的版本,每个 Class 对应一个运行时常量池

    • 字面量可以动态的添加(通过 String 类的 intern() 方法)
    • 符号引用可以被解析为直接引用
    • 运行时常量池包含字符串常量池和其它运行时常量
  3. 字符串常量池

    • 字符串池在JDK 1.7 之后被分离到堆区
    • 字符串常量池是 JVM 实例全局共享的,全局只有一个,存放的是字符串常量的引用值
    • 字符串常量池中的字符串只存在一份!(字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间)
  • JDK1.6:运行时常量池、字符串常量池是在方法区
  • JDK1.8:元空间(metaspace)成为方法区的新实现,运行时常量池、字符串常量池被移动到中。

创建字符串对象方式:

Java 中 String 创建对象过程及其运算原理

String 创建字符串的几种方式,以及在内存中的情况(JAVA)

Java 中创建 String 对象的两种方式

  1. 直接赋值方式创建,对象是在字符串常量池

    1
    String str = "hello";

    通过直接赋值方式创建字符串对象时,JVM 首先会对这个字符串进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回;如果不存在,则在字符串常量池中创建该字符串对象并且返回引用。

  2. 通过构造方法创建,字符串对象是在堆内存

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 在 new String 对象的时候,
    * 1.如果所需字符串在创建对象之前,就在常量池中已经存在了,那么:
    * 1.1 在堆里面创建一个对象,把字符串名指向这个对象;
    * 1.2 把这个对象的成员变量 value[] 的值指向常量池中的对象。
    * 2.如果所需字符串创建对象之前,在常量池中不存在:
    * 2.1 在堆里面创建一个对象,把字符串名指向这个对象;
    * 2.2 而常量池中没有值为所需字符串的对象,于是进行创建;
    * 2.3 然后字符串名指向的对象的成员变量 value[] 指向常量池值为"hello"这个对象就行了。
    */
    String str = new String("hello");

    通过构造方法来构造字符串对象时,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。

    • 使用构造方法进行 String 类对象实例化,产生的对象不会保存在对象池中,此对象无法重用。如果想将这个对象的引用加入到字符串常量池,只能通过手工入池方法完成:public native String intern();intern() 方法用于在运行时将字符串添加到内部的字符串池中。调用 intern() 后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。

注意事项:

  1. 实际开发中都是采用直接赋值方式,并且不要频繁修改,因为会产生垃圾空间;
  2. 开发中,在比较字符串内容是否相同时,一般将常量写在前面,这样避免 equals() 前面的字符串内容为 null,equals() 方法本身具有 null 判断的功能。

String 类常用方法:

特别地,trim() 方法用于删除字符串的头部和尾部空白,不包括字符串中间的空白。

StringBuilder 和 StringBuffer 类

当对字符串进行修改的时候,需要使用 StringBuilder 和 StringBuffer 类。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象。

StringBuilder 和 StringBuffer 类的 API详见源码

  • StringBuilder 和 StringBuffer 类的容量(capacity) 默认为 16,可以通过构造函数指定容量;如果通过构造函数传入的是字符串或是字符序列,那么 capacity 大小在字符串长度的基础上再加 16。

String、StringBuffer 和 StringBuilder 之间的区别

  • String 为字符串常量;StringBuffer、StringBuilder 均为字符串变量

  • 执行速度比较:StringBuilder > StringBuffer > String(大多数情况下)

    StringBuffer 和 StringBuilder 对象是变量,对变量操作就是对对象进行直接操作,不会进行创建,删除操作。因此在某些情况下 String 的执行速度是比较慢的,因为操作 String 对象时可能会有删除、新建操作。

  • 在线程安全方面,StringBuffer 中很多方法都被 synchronized 关键字修饰,所以可以保证线程是安全的。

    • 如果要进行的操作是多线程的,那么就要使用 StringBuffer;
    • 但是在单线程的情况下,建议使用速度比较快的 StringBuilder。

总结:

  • String 适合在少量字符串操作的情况下使用;
  • StringBuilder 适合单线程下在字符缓冲区进行大量操作的情况;
  • StringBuffer 适合多线程下在字符缓冲区进行大量操作的情况。

8. File 类

Java 文件类以抽象的方式代表文件名和目录路径名。该类主要用于文件和目录的创建、文件的查找和文件的删除等。

  • File 对象代表磁盘中实际存在的文件和目录。

构造方法:

  1. File(String pathname, int prefixLength)

  2. File(String child, File parent)

  3. File(String pathname)

    通过将给定路径名字符串转换成抽象路径名来创建一个新 File 实例

  4. File(String parent, String child)

    根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例

  5. File(File parent, String child)

    通过给定的父抽象路径名和子路径名字符串创建一个新的 File 实例

  6. File(URI uri)

    通过将给定的 file: URI 转换成一个抽象路径名来创建一个新的 File 实例

常用方法:

  1. 获取方法

    • public String getAbsolutePath() — 返回 File 的绝对路径名字符串

      • public String getPath() — 将此 File 转换为路径名字符串,获取构造路径
      • public String getName() — 返回此 File 表示的文件或目录的名称
      • public long length() — 返回此 File 表示的文件的字节大小
  2. 判断方法

    • public boolean exists() — 判断此 File 标识的文件或目录是否实际存在
    • public boolean isDirectory() — 判断此 File 标识的是否为文件夹
    • public boolean isFile() — 判断此 File 表示的是否为文件
  3. 创建和删除方法

    • public boolean creatNewFile() — 当且仅当不存在该名称的文件时,创建一个新的空文件
    • public boolean mkdir() — 创建由 File 表示的目录
    • public boolean mkdirs() — 创建由 File 表示的目录,包括任何必须但不存在的父目录
    • public boolean delete() — 删除由此 File 表示的文件或目录(只能删除文件或者空文件夹,不能删除非空文件夹)
  4. 遍历目录方法

    • public String[] list() — 返回一个 String 数组,表示该 File 目录中的所有子文件或目录的名称
    • public File[] listFiles() — 返回一个 File 数组,表示 File 目录中的所有子文件或目录的路径

注意事项:

  1. 一个 File 对象代表的是硬盘中的一个路径或者一个文件
  2. 无论该路径下是否存在文件或目录,都不影响 File 对象的创建