从new File("")到jdk源码

1. 概述

今天在项目中看到下面两行代码,看注释说是获取当前工作路径,之前也没有用过这种用法,比较好奇还能这样用,所以研究了一下源码。

//获取当前工作路径
File file = new File("");
String currentWorkDirectory = file.getAbsolutePath();

2. new File("")解析

首先,new File()是创建一个虚拟的文件(File)对象,通过这个对象可以调用很多方法来获取文件和目录的相关信息。以下列出一些常用方法:

2.1 File的常用方法

方法签名 作用
boolean delete() 删除文件或目录
void deleteOnExit() 在jvm退出时删除文件或目录
boolean createNewFile() 当以这个文件名命名的文件不存在时,创建一个新的空文件
boolean exists() 判断文件或目录是否存在
String getAbsolutePath() 获取File对象的绝对路径
String getName() 获取文件或目录名称
File getParentFile() 获取父File对象
String getPath() 获取File对象创建时传入的pathname参数
boolean isDirectory() 判断是否是目录
File[] listFiles() 列出当前目录下的所有文件
boolean mkdir() 创建单个目录
boolean mkdirs() 创建多级目录

2.2 new File("")做了什么

我们先来看看源码是怎么描述的:
image
其中注释的意思是:将指定的文件路径转换为一个绝对路径,然后创建一个新的File实例。如果给定的文件路径参数为空值,则返回空的绝对路径名。

官方的注释比较难理解,通俗的将就是,当我传入一个相对路径就会转换为绝对路径,当我传入一个""参数时,就只有一个绝对路径。那么这个绝对路径代表什么含义呢?

2.3 深入源码看File绝对路径(abstract pathname)的含义

2.3.1 File.getAbsolutePath()方法

其实我们可以看到new File(String pathname)这个构造方法只设置了相对路径和解析相对路径的长度。并没有有关绝对路径的操作。那么究竟是在哪里设置的绝对路径呢?这个就涉及到getAbsolutePath()方法了。

下面我们看一下getAbsolutePath()方法做了什么:
image
从注释可以看出,如果在new File()的时候传入的pathname已经是绝对路径的话,那么这个方法的返回就和getPath()一样,如果传入的是空字符串的话,那么就返回当前目录的路径,通过系统属性user.dir获取。

2.3.2 WinNTFileSystem.resolve()方法

那么我们继续往下看:
image

点进去resolve()方法可以看到返回值实际是从getUserPath()这个方法获取的。

image

2.3.3 WinNTFileSystem.getUserPath()方法

getUserPath()方法调用了System.getProperty("user.dir")方法来获取user.dir这个key的配置。再往里面看user.dir的值其实是从props这个Properties对象中获取的。

image

2.3.4 System.setProperties(props)方法

那props又是从哪里拿到这个值的呢?我们接着往下看:
在System类里面对着props这个属性用ctrl+鼠标左键查找props在哪几个地方使用了。可以看到有一个setProperties(Properties props)方法。再对着setProperties这个方法使用ctrl+鼠标左键查找。
image

2.3.5 Process.main()方法

在com.sun.org.apache.xalan.internal.xslt.Process的main方法里面我们可以看到,执行了System.setProperties(props),而System.setProperties(props)调用了本地方法private static native Properties initProperties(Properties props)对props进行初始化。

image

2.3.6 System.initProperties(Properties props)本地方法

image

到这里的话,其实java源代码已经结束了,总结来说就是jvm在启动的时候调用了System类的private static native Properties initProperties(Properties props)本地方法对props属性进行初始化,设置了user.dir的值。

这时可能还有些好奇宝宝不甘心,为什么调用了这个本地方法就可以获取user.dir的值,那么我们就来研究一下openjdk的c语言源码吧。

2.4 深入openjdk源码

我们从github上搜索到openjdk的源码仓库,随便找一个java8的tag来研究initProperties()这个本地方法到底做了什么。
github的openjdk代码仓库

  1. 首先我们找到jdk/src/share/native/java/lang目录下面的System.c文件。在里面搜索一下initProperties,可以看到有一个Java_java_lang_System_initProperties方法。
    image

  2. 接着我们在这个方法里面搜索user_dir,可以看到值是从一个sprops指针中获取的,而sprops从上一张图可以看出是从GetJavaProperties(env)这个方法获取的值。
    image

  3. 那我们ctrl+shift+F全局搜索一下GetJavaProperties这个方法。可以看到jdk/src/windows/native/java/lang/java_props_md.c文件中有这个方法,从文件路径可以看出这个文件是windows系统下执行的。
    image

  4. 接着在这个方法里面搜索user_dir,可以看到user_dir实际是从GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR), buf)方法里面获取值的。GetCurrentDirectoryW这个方法就是windows的系统函数,用来获取当前工作目录。
    image

到这里jdk源码解析就结束了,可以看到在windows系统下是调用了它的系统函数获取当前工作目录。

备注:_wcsdup(buf)方法是c语言的库函数,作用是分配一块新的空间,然后从buf数组里面获取值赋值给新创建的空间。

3. 总结

  1. 绝对路径是什么:当前工作目录,就是当前项目的根路径
  2. 使用new File("")创建File对象时,绝对路径其实是getAbsolutePath()方法获取的,new File("")只是设置了path=""
  3. System.props这个属性其实包含了很多值,如:java.version、user.home等等,可以看源码中的注释
  4. 通过System.getProperty(key)可以获取系统的一些配置信息
posted @ 2022-08-25 00:59  竹堑  阅读(325)  评论(0编辑  收藏  举报