1. Junit单元测试
测试的分类:黑盒测试(无需代码,给定输入看输出),白盒测试(需要写代码看代码的执行流程)
2. Java反射
反射的概念主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,相当于一面精子,反映到程序中,反射就是用来知道这个类中有什么成员,以及别的类中有什么成员。
这看起来破坏了封装的特性,甚至让私有的变量都能被外部访问,让类不在那么安全。为啥要有反射呢?反射的作用主要有以下三个方面:
- 反射让开发人员可以通过外部类的全路径名创建对象,并使用这些类,实现一些扩展的功能
- 反射让开发人员可以枚举出类的全部成员,包括构造函数、属性、方法。以帮助开发者写出正确的代码。
- 测试时可以利用反射API访问类的私有成员,以保证测试代码覆盖率。
获取类的三种方式
1 | // 1.通过字符串获取Class对象,这个字符串必须带上完整路径名 |
- 第一种方法是通过类的全路径字符串获取Class对象,这也是最常用的反射获取Class对象的方法
- 第二种方法有限制条件:需要导入类的包
- 第三种方法已经有了Student对象,也就不需要再反射了
获取到类之后,我们可以进行接下来的一系列操作:
获取成员变量
获取字段有两个 API:getDeclaredFields
和getFields
。他们的区别是:getDeclaredFields
用于获取所有声明的字段,包括公有字段和私有字段,getFields
仅用来获取公有字段:
1 | // 1.获取所有声明的字段 |
获取构造方法
获取构造方法同样包含了两个 API:用于获取所有构造方法的 getDeclaredConstructors
和用于获取公有构造方法的getConstructors
:
1 | /**获取构造方法**/ |
获取非构造方法
同样地,获取非构造方法的两个 API 是:获取所有声明的非构造函数的 getDeclaredMethods
和仅获取公有非构造函数的 getMethods
:
1 | // 1.获取所有声明的函数 |
应用的代码如下
1 | import java.lang.reflect.Constructor; |
1 | import java.lang.reflect.Constructor; |
3. java继承
多个类中存在相同的属性和行为的时候,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只需要继承那个类即可。多个类可以称为子类,单独这个类称为父类。子类可以直接访问父类中的非私有的属性和行为。
继承的作用:(1)提高代码的复用性;(2)让类与类之间产生了关系,是多态的前提。
java只支持单继承,不支持多继承。java支持多重继承。使用继承的时候不要为了继承部分功能,而去使用继承。
super是一个关键字,代表父类的存储空间标识,可以理解为父类的引用。super和this的用法类似,this表示当前对象的引用,谁调用就代表谁。super代表当前子类对父类的引用。
当子类和父类出现同名成员的时候,可以使用super进行区分;子类要调用父类的构造函数时,可以使用super语句。
方法的重写,子类中出现与父类一模一样的方法时,除了权限修饰符,权限符大于private,返回值类型,方法名和参数列表一样。这个时候会出现覆盖的操作,也称为重写。
覆盖的时候必须要注意:
- 覆盖时,子类方法的权限一定要大于等于父类方法权限
- 静态只能覆盖静态
覆盖的使用场景:当子类需要父类的功能,而功能主体子类有自己的特有内容的时候,可以复写父类中的方法。
方法的重写和重载的区别:方法的重写在子类方法与父类方法一样,除了权限修饰符;而重载用在同一个类中各个方法方法名相同,参数列表不同的情况。
子父类中构造的用法:
- 子类的过程初始化的过程中,首先回去执行父类的初始化动作。因为子类的构造方法中默认有一个super(),子类要使用父类的成员变量,这个初始化,必须在子类初始化之前完成。所以,子类的初始化过程中,会先执行父类的初始化。
- 如果父类没有无参构造方法:使用super调用父类的待参构造(推荐方式)
执行顺序:父类静态代码块→子类静态代码块→父类构造代码块→父类构造方法→子类构造代码块→子类构造方法
final关键字
final是一个关键字,用来修饰类,成员变量和成员方法。
特点:
- 它修饰的类不能被继承
- 他修饰的成员变量是一个常量
- 它修饰的成员方法是不能被子类重写的
final修饰的常量定义一般都有书写的规范,被final修饰的常量名称,所有字母都要大写
final修饰成员变量,必须初始化,初始化有两种:
- 显式初始化
- 构造方法初始化
final和private的区别:
- final修饰的类可以访问,private不能修饰外部类,但是可以修饰内部类
- final修饰的方法不能被子类重写,private修饰的方法表面上看可以被子类重写,其实是不可以的,子类是看不到父类的私有方法的。
- final修饰的变量只能在显示初始化或者构造函数初始化时赋值一次,以后不能修改;private修饰的变量,也不允许直接被子类或包中的其他类访问或者修改,但是可以通过get和set方法对其改值和取值。
多态
对象在不同的时刻表现出来的不同状态。
多态的前提:
- 要有继承或者实现关系
- 要有方法的重写
- 要有父类引用指向子类对象
程序中体现为:父类或者接口的引用指向或者接收自己的子类对象
好处:多态的存在提高了程序的可扩展性和后期可维护性
弊端:父类的调用时只能调用父类里面的方法,不能调用子类的特有方法,因为并不清楚将来将有什么样的子类来继承。
多态成员的特点:
成员变量:
编译时期:看引用变量所属的类中是否有所调用的变量
运行时期:也是看引用型变量所属的类是否有调用的变量
成员变量无论编译还是运行都看引用型变量所属的类,简单记为成员变量编译和运行都看左边
成员方法:
编译时期:要看引用变量所属的类中是否有所调用的成员
运行时期:要看对象所属的类中是否有所调用的成员。如果父子出现同名的方法,因为方法有覆盖的特性,编译看左边,运行看右边
静态方法:
编译时期:看的引用型变量所属的类中是否有所调用的变量
运行时期:也是看引用型变量所属的类是否有调用的变量
编译和运行都看等号左边
一定不能够将父类的对象转换成子类类型
父类的引用指向子类对象,该引用可以被提升,也可以被强制转换,多态自始至终都是子类对象在变化。
1 | public class polymorphism { |
实现多态的很重要的一点就是向上转型,在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备既能调用父类的方法,又能调用子类的方法。什么是向上转型?假设:A b = new A();实例化了一个A的对象,但是如果定义A b= new a();(a是A的子类)定义了一个A的类型b,但是是由a对象来实例化的,也就是用子类来实例化的。有时候子类中有需要对父类中的某些方法进行重写,然后调用方法的时候就会调用子类重写的方法而不是原本父类的方法。向上转型后,子类单独定义的方法会丢失(即子类重载父类中的方法),而子类中重写了父类的方法,当调用的时候,就会调用重写的方法。
上述的代码win1重载了tostring()方法,重写了Tostring()方法,因为向上转型的原则,先会调用父类中的tostring()方法(子类中的tostring()重载后丢失),在调用子类中的Tostring()方法。
如果同时将子类中的两个方法都重载:
1 | public void tostring(String name){//重载父类中的tostring |
那么输出的都是父类的方法
抽象
抽象就是从多个事物中将共性的,本质的内容抽象出来。
抽象类:java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。
由来:多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取的过程中,只抽取了功能定义,并未抽取功能主体,那么只功能声明,没有功能主体的方法称为抽象方法。
抽象类的特点:
- 抽象方法一定在抽象类中
- 抽象方法和抽象类都必须被abstract关键字修饰
- 抽象类不可以用new创建对象,因为调用抽象方法没有意义
- 抽象类中的抽象方法要被使用的话,必须由子类复写其所有的抽象方法后,建立子类对象调用;如果子类只覆盖了部分的抽象方法,那么该子类还是一个抽象类
- 抽象类中可以有抽象方法,也可以有非抽象的方法,抽象方法用于子类的实例化
- 如果一个类是抽象类,那么继承它的子类,要么是抽象类,要么重写所有的抽象方法
- 特殊的,抽象类可以不定义抽象方法,这样做仅仅是不让该类建立对象
抽象类的成员特点:
- 成员变量:可以是变量,也可以是常量
- 构造方法:有构造方法
- 成员方法:可以是抽象方法,也可以是非抽象方法
1 | public class AbstractClass { |
抽象类需要注意的有:
抽象类不能被实例化,但为什么还有构造函数?因为只要是class定义的类里面就有构造函数,抽象类中的函数是给子类实例化的。一个类没有抽象方法的话,如果不想被继承还不想被实例化,那么考虑定义为抽象类。
抽象类不能跟下面的关键词共存:
- final:final不可以被覆盖,但是如果方法被抽象那就需要被覆盖,所以冲突
- private:如果函数私有了,子类无法直接访问,所以无法覆盖
- static:不需要对象,类名就可以调用抽象方法,调用抽象方法没有意义
接口
接口是抽象方法和常量值的集合,从本质上讲,接口是一种特殊的抽象类,这种抽象类只包含常量和方法的定义,而没有变量和方法的实现。
格式:interface 接口名{}
接口的出现将多继承通过另一种形式表现出来,即多实现
实现:class 类名 implements 接口名{}
特点:
- 接口不能被实例化
- 一个类如果实现了接口,要么是抽象类,要么实现接口中的所有方法
接口成员的特点:
接口中的成员修饰符是固定的。
- 成员变量:public static final,接口里定义的是全局变量,而且修饰符只能是这三个关键字,都可以省略,常量名要大写
- 成员方法:public abstract,接口里定义的方法都是抽象的,两个修饰符关键字可以省略。
继承与实现的区别:
- 类与类之间称为继承关系:因为该类无论是抽象的还是非抽象的,它的内部都可以定义非抽象方法,这个方法可以直接子类使用,子类继承即可。只能单继承,可以多层继承。
- 类与接口之间是实现关系:因为接口中的方法都是抽象的,必须由子类实现才可以实例化。可以单实现,还可以在继承一个类的同时实现多个接口(class) extends (class) implements (interface1,interface2…))
- 接口与接口之间是单继承关系:一个接口可以继承另一个接口,并添加新的属性和抽象方法,并且接口可以多继承。
抽象类和接口的区别:
成员变量:
- 抽象类能有变量也可以有常量
- 接口只能有常量
成员方法:
- 抽象类可以有非抽象的方法,也可以有抽象的方法
- 接口只能有抽象的方法
构造方法:
- 抽象类有构造方法
- 接口没有构造方法
类与抽象类和接口的关系:
- 类与抽象类的关系是继承extends
- 类与接口的关系是实现implements
接口的思想特点:
- 接口是对外暴露的规则;
- 接口是程序的功能扩展;
- 接口的出现降低耦合性;(实现了模块化开发,定义好规则,每个人实现自己的模块,大大提高了开发效率)
- 接口可以用来多实现;
- 多个无关的类可以实现同一个接口;
- 一个类可以实现多个相互直接没有关系的接口;
- 与继承关系类似,接口与实现类之间存在多态性。
内部类
将一个类定义在另一个类中,里面那个类就成为内部类。
访问特点:
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。 内部类分类及共性:
共性:
- 内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。
成员内部类
在外部类中有成员变量和成员方法,成员内部类就是把整个一个类作为了外部类的成员; 成员内部类是定义在类中方法外*的类; 创建对象的格式为:外部类名.内部类名 对象名 = 外部类对象.内部类对象*; 成员内部类之所以可以直接访问外部类的成员,那是因为内部类中都持有一个外部类对象的引用:*外部类名.this*; 成员内部类可以用的修饰符有final,abstract,public,private,protected,static.
静态内部类
静态内部类就是成员内部类加上静态修饰符static,定义在*类中方法外*。
在外部类中访问静态内部类有两种场景:
- 在外部类中访问静态内部类中非静态成员:外部类名.内部类名 对象名 = 外部类名.内部对象,需要通过创建对象访问;
- 在外部类中访问静态内部类中的静态成员:同样可以使用上面的格式进行访问,也可以直接使用*外部类名.内部类名.成员*。
局部内部类
局部内部类是定义在方法中的类。
- 方法内部类只能在定义该内部类的*方法内*实例化,不可以在此方法外对其实例化。
- 方法内部类对象不能使用该内部类所在方法的非final局部变量。
可以用于方法内部类的修饰符有final,abstract;
静态方法中的方法内部类只能访问*外部的静态成员*。
匿名内部类
匿名内部类是内部类的简化写法,是建立一个带内容的外部类或者接口的子类匿名对象。 前提: 内部类可以继承或实现一个外部类或者接口。 格式: new 外部类名或者接口名(){重写方法}; 通常在方法的形式参数是接口或者抽象类,并且该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
4. static关键字
通常来说,当创建类的时候,就是在描述那个类的对象的外观和行为,除非用new来创建那个类的对象,否则,实际上并未获得任何对象。执行new来创建对象的时候,类型存储空间才被分配,其方法才供外界调用。
上述方法无法解决两种情况:1. 只想为某特定域分配单一存储空间,而不去考虑究竟要创建多少对象,甚至根本就不创建任何对象; 2. 希望某个方法不与包含它的类的任何对象关联在一起,也就是说,即使没有创建对象,也能够调用这个方法。
解决这两个问题的方法就是使用static关键字,当声明一个对象是static时,就意味着这个域或方法不会与包含它的那个类的任何对象实例关联在一起。即使从未创建某个类的任何对象,也可以调用其static方法或访问其static域。
例如:
1 | class StaticTest{ |
那么在java里面st1.i和st2.i指向同一个存储空间,这两个对象共享一个i。引用static变量既可以通过新建一个对象去引用,,也可以通过类名直接去引用
1 | StaticTest.i ++; |
使用类名来引用static变量是首选,这不仅是因为它强调了变量的static结构,而且在某些情况下它还为编译器进行优化提供了更好的机会。同理来说,static方法也可以这样来调用。
5. java泛型
java泛型的目的之一就是用来指定容器需要持有什么类型的对象,而且由编译器来保证其类型的正确性。
元组类库
定义的泛型类并不一定要传入泛型类型的实参,在使用泛型的时候,如果传入实参,则会根据传入的泛型实参做相应的限制。如果没有传入泛型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何类型。
由于return语句只能返回单个对象,因此需要考虑创建一个对象,用它来持有想要返回的多个对象。那么这个概念就叫做元组,它是将一组对象直接打包存储于其中的一个单一的对象。这个容器允许读取其中的元素,但是不允许向其中存放新的对象。
1 | public class TwoTuple <A, B>{ |
上面的代码中,虽然使用public的对象first和second,但是由于使用了final关键字,所以即使外界代码可以调用他,但是仍然不能更改他。下面是通过继承将其扩展为三元组的代码。
1 | public class ThreeTuple<A, B, C> extends TwoTuple<A, B>{ |
下面的代码既用链表的方式实现了栈,更重要的是内部类和外部类都是用到了泛型的方法。也使用了一个末端哨兵来判断栈何时为空。
泛型接口
泛型可以用作接口,例如生成器,这是一种专门负责创建对象的类。当使用生成器创建新的对象的时候,并不需要任何参数,而工厂方法一般需要参数。也就是生成器无需额外的信息就知道如何创建新对象。
1 | /**泛型接口**/ |
已知Integer是Number的一个子类,那么Generic
可以将上面的方法改写一下:
1 | public void showKeyValue1(Generic<?> obj){ |
这里就是类型通配符,此处的?代替具体的类型参数。此处?是类型实参,而不是类型参数!此处?是类型实参,而不是类型形参!
泛型方法
泛型类是在实例化类的时候指明泛型的具体类型;泛型方法是在调用方法的时候指明泛型的具体类型。
1 | /** |
1 | public class GenericTest { |
静态方法有一种需要注意,就是在类中的静态方法使用泛型:静态方法无法访问类上定义的泛型,如果静态方法操作的引用数据类型不确定时,必须要将泛型定义在方法上。静态方法要使用泛型的话,必须将静态方法也定义为泛型方法。
在java中不能创建一个确切的泛型类型的数组,也就是下面的是不可以的:
1 | List<String>[] ls = new ArrayList<String>[10]; |
而是用通配符创建泛型数组是可以的,比如:
1 | List<?>[] ls = new ArrayList<?>[10]; |
6. 抽象类
在面向对象中,所有的对象都是通过类来描述的,但是并不是所有的类都是用来描述对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。
抽象类除了不能实例化对象外,类的其他功能依旧存在,成员变量、成员方法和构造方法的访问方式和普通类一样。由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。在 Java 中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。
1 | public abstract class Employee { |
如果是要实现抽象方法,在类中抽象方法只包含一个方法名,不包括方法体。抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。
1 | public abstract double computePay(); |
抽象方法会造成以下两个结果:
- 如果一个类包含抽象方法,那么该类必须是抽象类
- 任何子类必须重写父类的抽象方法,或者声明自身为抽象类
7. 枚举
java枚举也是一个特殊的类,一般表示一组常量,比方一年的四个季节,12个月份等等。java使用enum关键字来定义枚举,各个常量使用逗号来分割。
1 | enum Color{ |
实现的应用实例如下(当然在内部类中也可以使用枚举):
1 | public class EnumTest { |
enum定义的枚举类默认继承了java.lang.Enum类,并实现了 java.lang.Serializable 和 java.lang.Comparable 两个接口。values(),ordial()和valueOf()方法均位于java.lang.Enum类中。
8. java注解
java语言中的类,方法,变量,参数和包都可以被标注。java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。java虚拟机可以保留标注内容,在运行时可以获取到标注内容。当然它也支持自定义的java标注。
内置的注解
java定义了一套注解,一共有7个,3个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
作用在代码中的注解是:
- @Override:检查该方法是否为重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated:标记过时方法,如果使用该方法,会报编译警告。
- @SuppressWarnings:指示编译器去忽略注解中声明的警告
作用在其他注解的注释(元注解):
- @Retention:标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Documented - 标记这些注解是否包含在用户文档中。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
上图是annotation架构的图像,其中一个annotation和一个retentionPolicy关联,一个annotation和1-n个ElementType关联,annotation有多个实现类,包括右边的部分。
这里可以看出,annotation是一个接口,其分支是实现这个接口的类,
1 | package java.lang.annotation; |
其中ElementType是一个enum类,用来指定annotation的类型:
1 | package java.lang.annotation; |
RetentionPolicy也是一个enum类,用来指定annotation的策略,不同RetentionPolicy类型的RetentionPolicy类型的annotation的作用域不同:
1 | package java.lang.annotation; |
- 若 Annotation 的类型为 SOURCE,则意味着:Annotation 仅存在于编译器处理期间,编译器处理完之后,该 Annotation 就没用了。 例如," @Override" 标志就是一个 Annotation。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"@Override" 就没有任何作用了。
- 若 Annotation 的类型为 CLASS,则意味着:编译器将 Annotation 存储于类对应的 .class 文件中,它是 Annotation 的默认行为。
- 若 Annotation 的类型为 RUNTIME,则意味着:编译器将 Annotation 存储于 class 文件中,并且可由JVM读入。
常用的annotation:
1 | -- 所标注内容,不再被建议使用。 |
annotation的作用
annotation是一个辅助类,作用有:
编译检查
annotation可以让编译器进行编译检查,比方说如果有个方法被@override标注,则意味着该方法会覆盖父类中的同名方法。如果有方法被@override标识,但是父类中没有被@override标注的同名方法,则编译器会报错。
在反射中使用annotation
1 | import java.lang.annotation.Annotation; |
根据annotation生成帮助文档
通过加上@Documented标签,能使得该annotation标签出现在javadoc中。
能帮忙查看代码
通过 @Override, @Deprecated 等,我们能很方便的了解程序的大致结构。
另外,我们也可以通过自定义 Annotation 来实现一些功能。
9. 异常处理
异常包含以下三个类型:
- 检查性异常:最具代表性的检查性异常就是用户错误或问题引起的异常,例如要打开一个不存在的文件时,一个异常就发生了,这些异常在编译时不能被简单的忽略。
- 运行时异常:运行时异常可以在编译时被忽略
- 错误:错误不是异常,而是脱离程序员控制的问题。比方说一个栈溢出了,错误就产生了,他们在编译的时候是检测不到的。
所有的异常类都是从java.lang.Exception类继承的子类。
实现异常的捕获是用try/catch语句的:
1 | try { |
如果一个关键字没有捕获到一个检查性异常,那么该方法就必须使用throws关键字来声明,throws关键字放在方法签名的尾部。也可以使用throw关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
1 | import java.io.*; |
finally关键字用来创建try代码块后面执行的代码块,无论是否发生异常,finally代码块中的代码都会被执行。在finally代码块中可以运行清理类型等收尾善后工作。
1 | public class ExcepTest{ |
注意以下事项:
- catch不能独立于try而存在
- 在try/catch后面添加finally块并非强制性要求的
- try代码后不能既没有catch又没有finally块
- try,catch,finally之间不能添加任何元素
如果我们需要自定义异常,编写的时候需要注意:
- 所有的异常都必须是Throwable的子类
- 如果希望写一个检查性的异常类,则需要继承Exception类
- 如果希望写一个运行时异常类,那么需要继承 RuntimeException 类
1 | public class InsufficientFundsException extends Exception { |
10. java io流
Java.io包中的流支持很多种格式,比如基本类型,对象,本地化字符集等等。一个流可以理解为一个数据的序列,输入流表示从一个源读取数据,输出流表示向一个目标写数据。
java的控制台输入由Systm.in完成,可以创建一个BufferedReader()来获取一个字符流。
1 | BufferedReader br = new BufferedReader(new |
br可以通过read()或者readLine()函数读取一个字符串,
1 | import java.io.*; |
控制台的输出由print()和println()完成,这些方法都由PrintStream定义,System.out是该类对象的一个引用,PrintStream继承了OutputStream类,并且实现了方法write(),可以往控制台进行写操作。
1 | public class WriteDemo { |
java IO流的整个框架如上图所示,重要的是FileInputStream 和 FileOutputStream。
FileInputStream
该流用于从文件中读取数据,它的对象可以通过关键字new来创建。创建的方法如下:
1 | /**方法一:使用字符串类型的文件名创建**/ |
这个类实现之后,就会提供一系列的方法提供使用。
FileOutputStream
该类用来创建一个文件并向文件中写入数据,如果该流在打开文件进行输出前,目标文件并不存在,那么流会创建该文件。创建该流的方法如下:
1 | /**方法一:使用字符串类型的文件名创建**/ |
一个简单的应用如下:
1 | import java.io.FileInputStream; |
文件和IO
目录
java File 类中有两个方法可以用来创建文件夹:
- mkdir( )方法创建一个文件夹,成功则返回true,失败则返回false。失败表明File对象指定的路径已经存在,或者由于整个路径还不存在,该文件夹不能被创建。
- mkdirs()方法创建一个文件夹和它的所有父文件夹。
读取目录
一个目录其实就是一个 File 对象,它包含其他文件和文件夹。如果创建一个 File 对象并且它是一个目录,那么调用 isDirectory() 方法会返回 true。可以通过调用该对象上的 list() 方法,来提取它包含的文件和文件夹的列表。
1 | import java.io.File; |
删除目录
删除文件可以用 java.io.File.delete() 方法。
1 | import java.io.File; |