源代码:
public File[] listFiles() {
String[] ss = list();
if (ss == null) return null;
int n = ss.length;
File[] fs = new File[n];
for (int i = 0; i < n; i++) {
fs[i] = new File(ss[i], this);
}
return fs;
}
如图:
源码解析:
public File[] listFiles() {
// 1. 调用list()方法获取当前目录下的文件名数组(String类型)
String[] ss = list();
// 2. 如果list()返回null(目录不存在/无权限/不是目录等),直接返回null
if (ss == null) return null;
// 3. 获取文件名数组的长度
int n = ss.length;
// 4. 创建与文件名数组长度相同的File对象数组
File[] fs = new File[n];
// 5. 遍历所有文件名
for (int i = 0; i < n; i++) {
// 6. 为每个文件名创建File对象:
// ss[i] : 文件名(相对路径)
// this : 当前File对象(父目录)
// 组合成完整路径: 父目录路径 + 文件分隔符 + 文件名
fs[i] = new File(ss[i], this);
}
// 7. 返回File对象数组
return fs;
}
解读太抽象了,我们具体来说
假设当前File对象表示目录“/home/user”,并且该目录下有两个文件:“a.txt”和“b.txt”。
那么,`list()`方法返回的字符串数组ss为:["a.txt", "b.txt"]。
然后,我们创建一个长度为2的File数组。
在循环中,对于每个文件名,我们创建新的File对象:
- 第一个:new File("a.txt", this) -> 相当于路径为“/home/user/a.txt”
- 第二个:new File("b.txt", this) -> 相当于路径为“/home/user/b.txt”
因此,返回的File数组就包含了这两个文件的File对象。
但是,这里有一个重要的点:`list()`方法返回的数组中的每一项(文件名)是依赖于底层文件系统的。例如,在Unix系统上,隐藏文件(以'.'开头的文件)也会被包含在内,而在某些系统上可能不会包含特殊文件(如设备文件、命名管道等)或符号链接,这取决于底层操作系统的实现。
另外,`listFiles()`方法返回的数组中的顺序是不确定的,通常与底层文件系统返回的顺序一致,因此不能依赖于特定的顺序。 最后,需要注意的是,如果目录中没有任何文件,则`list()`方法返回一个长度为0的数组(不是null),那么`listFiles()`方法就会返回一个长度为0的File数组。
总结调用过程:
- - 检查当前File对象是否是一个可读的目录(这一步在`list()`方法内部完成,如果不符合条件则返回null)。
- - 获取目录下的所有文件名(字符串形式)。
- - 将这些文件名转换为相对于当前目录的File对象。
- - 返回File数组。 如果调用者没有足够的权限访问该目录,或者该File对象不是一个目录,那么`list()`方法返回null,因此`listFiles()`也返回null。