从今天开始阅读Java源码吧——Java.io.File.java

依赖关系

package java.io;

import java.net.URI;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.util.List;
import java.util.ArrayList;
import java.security.AccessController;
import java.security.SecureRandom;
import java.nio.file.Path;
import java.nio.file.FileSystems;
import sun.security.action.GetPropertyAction;

通过这里我们先搞清楚谁是爸爸谁是儿子,看不懂的地方可以从这再去找。

类的定义

    public class File implements Serializable, Comparable<File> {
    ...
    }

重要的成员变量

private static final FileSystem fs = DefaultFileSystem.getFileSystem();
private final String path;

fs为一个FileSystem类型的静态最终变量,不可改变。初始化为DefaultFileSystem.getFileSystem();。如果你去源码中去寻找,你会发现这个:

class DefaultFileSystem {

    /**
     * Return the FileSystem object for Windows platform.
     */
    public static FileSystem getFileSystem() {
        return new WinNTFileSystem();
    }
}

一看就是安装了Windows版本的JDK,感兴趣的话可以去看看Linux版本的JDK,一定有所不同。

构造函数

    private File(String pathname, int prefixLength) {
        ...
    }

    private File(String child, File parent) {
       ...
    }

    public File(String parent, String child) {
        ...
    }

    public File(File parent, String child) {
        ...
    }

    public File(URI uri) {
        ...
    }

    public File(String pathname) {
        if (pathname == null) {
            throw new NullPointerException();
        }
        this.path = fs.normalize(pathname);
        this.prefixLength = fs.prefixLength(this.path);
    }

共有2个私有,4个公有的构造函数。也许有一天,面试官提出问题:

  • 问:构造函数可以是私有的吗?
  • 答:可以,我读过Java.io.File.java,源码里面就有两个私有的构造方法。

深藏功与名。
当然知其然知其所以然,私有的构造方法多用于单例模式。或者说这个类干脆就不想让别人实例化,此时就可以使用唯一私有的构造函数完成目标。
回到构造函数,我们看最简单的参数为String pathname的构造函数。首先检测是否为空,若为空抛出异常,若不为空则对path与prefixLength(前缀长度)赋值。两个函数均来自java.nio.file.FileSystems,或许我们应该先从它开始学习的。

函数分析

    private static enum PathStatus { INVALID, CHECKED };

    private transient PathStatus status = null;

    final boolean isInvalid() {
        if (status == null) {
            status = (this.path.indexOf('\u0000') < 0) ? PathStatus.CHECKED
                                                       : PathStatus.INVALID;
        }
        return status == PathStatus.INVALID;
    }

很简单的判断路径是否有效,判断条件为this.path.indexOf('\u0000') < 0,我是肯定不会这么写,我会写的特别的丑。而使用enum枚举去判断路径状态,要是我写的话可能就是个Boolean吧。

    /**
     * The length of this abstract pathname's prefix, or zero if it has no
     * prefix.
     */
    private final transient int prefixLength;

    /**
     * Returns the length of this abstract pathname's prefix.
     * For use by FileSystem classes.
     */
    int getPrefixLength() {
        return prefixLength;
    }

从这里我们看得出来File类引入了一个概念即——abstract path。注意这并不是相对路径,而是抽象路径。Java提出这个概念的理由是Unix与Windows系统下,路径的分割符号不同。前者为’/’,后者为’\’,为了统一路径表达方式才引入了抽象路径。

访问控制

public boolean canRead() {
        ...
    }

    public boolean canWrite() {
        ...
    }

    public boolean exists() {
        ...
    }

    public boolean isDirectory() {
       ...
    }

    public boolean isFile() {
        ...
    }

    public boolean isHidden() {
        ...
    }

    public long lastModified() {
        ...
    }

    public long length() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkRead(path);
        }
        if (isInvalid()) {
            return 0L;
        }
        return fs.getLength(this);
    }

这几个函数写法都很类似,都先是调用SecurityManager.checkRead(path)函数进行一次检查。之后调用上面读过的isValid()函数判断文件是否合法。最后按照不同函数功能调用FileSystem的函数去实现。再往后看,你会发现整个这个类里面90%的函数都是这个格式,最终还是调用对应操作系统FileSystem中的相关函数完成相应功能的。

一些重写的方法

    public int compareTo(File pathname) {
        return fs.compare(this, pathname);
    }

    public boolean equals(Object obj) {
        if ((obj != null) && (obj instanceof File)) {
            return compareTo((File)obj) == 0;
        }
        return false;
    }

    public int hashCode() {
        return fs.hashCode(this);
    }

    public String toString() {
        return getPath();
    }

简单到一眼看过去就明白的地步,toString()函数还非要调用一下getPath(),这么写不也挺好吗:

    public String toString() {
        return path;
    }

源码当然也是可以随意修改的,只要你觉得理解没问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值