从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("")做了什么
我们先来看看源码是怎么描述的:
其中注释的意思是:将指定的文件路径转换为一个绝对路径,然后创建一个新的File实例。如果给定的文件路径参数为空值,则返回空的绝对路径名。
官方的注释比较难理解,通俗的将就是,当我传入一个相对路径就会转换为绝对路径,当我传入一个""参数时,就只有一个绝对路径。那么这个绝对路径代表什么含义呢?
2.3 深入源码看File绝对路径(abstract pathname)的含义
其实我们可以看到new File(String pathname)这个构造方法只设置了相对路径和解析相对路径的长度。并没有有关绝对路径的操作。那么究竟是在哪里设置的绝对路径呢?这个就涉及到getAbsolutePath()方法了。
下面我们看一下getAbsolutePath()方法做了什么:
从注释可以看出,如果在new File()的时候传入的pathname已经是绝对路径的话,那么这个方法的返回就和getPath()一样,如果传入的是空字符串的话,那么就返回当前目录的路径,通过系统属性user.dir获取。
那么我们继续往下看:
点进去resolve()方法可以看到返回值实际是从getUserPath()这个方法获取的。
getUserPath()方法调用了System.getProperty("user.dir")方法来获取user.dir这个key的配置。再往里面看user.dir的值其实是从props这个Properties对象中获取的。
那props又是从哪里拿到这个值的呢?我们接着往下看:
在System类里面对着props这个属性用ctrl+鼠标左键查找props在哪几个地方使用了。可以看到有一个setProperties(Properties props)方法。再对着setProperties这个方法使用ctrl+鼠标左键查找。
在com.sun.org.apache.xalan.internal.xslt.Process的main方法里面我们可以看到,执行了System.setProperties(props),而System.setProperties(props)调用了本地方法private static native Properties initProperties(Properties props)对props进行初始化。
到这里的话,其实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代码仓库
首先我们找到jdk/src/share/native/java/lang目录下面的System.c文件。在里面搜索一下initProperties,可以看到有一个Java_java_lang_System_initProperties方法。
接着我们在这个方法里面搜索user_dir,可以看到值是从一个sprops指针中获取的,而sprops从上一张图可以看出是从GetJavaProperties(env)这个方法获取的值。
那我们ctrl+shift+F全局搜索一下GetJavaProperties这个方法。可以看到jdk/src/windows/native/java/lang/java_props_md.c文件中有这个方法,从文件路径可以看出这个文件是windows系统下执行的。
接着在这个方法里面搜索user_dir,可以看到user_dir实际是从GetCurrentDirectoryW(sizeof(buf)/sizeof(WCHAR), buf)方法里面获取值的。GetCurrentDirectoryW这个方法就是windows的系统函数,用来获取当前工作目录。
到这里jdk源码解析就结束了,可以看到在windows系统下是调用了它的系统函数获取当前工作目录。
备注:_wcsdup(buf)方法是c语言的库函数,作用是分配一块新的空间,然后从buf数组里面获取值赋值给新创建的空间。
3. 总结
- 绝对路径是什么:当前工作目录,就是当前项目的根路径
- 使用new File("")创建File对象时,绝对路径其实是getAbsolutePath()方法获取的,new File("")只是设置了path=""
- System.props这个属性其实包含了很多值,如:java.version、user.home等等,可以看源码中的注释
- 通过System.getProperty(key)可以获取系统的一些配置信息
从new File("")到jdk源码的更多相关文章
- eclipse调试jdk源码
摘要 介绍使用eclipse调试jdk源码 java是一门开源的程序设计语言,喜欢研究源码的java开发者总会忍不住debug一下jdk源码.虽然官方的jdk自带了源码包src.zip,然而在debu ...
- jdk源码调试功能
JDK源码重新编译——支持eclipse调试JDK源码--转载 最近在研究jdk源码,发现debug时无法查看源码里的变量值. 因为sun提供的jdk并不能查看运行中的局部变量,需要重新编译一下rt. ...
- JDK源码重新编译——支持eclipse调试JDK源码--转载
最近在研究jdk源码,发现debug时无法查看源码里的变量值. 因为sun提供的jdk并不能查看运行中的局部变量,需要重新编译一下rt.jar. 下面这六步是编译jdk的具体步骤: Step 1: ...
- Eclipse用法和技巧二十三:查看JDK源码
使用java开发,如果能阅读JDK的经典代码,对自己的水平提高是很有帮助的.笔者在实际工作中总结了两种阅读JDK源码的方式.第一种下载android源代码,直接在android源码代码中,这里的代码虽 ...
- eclipse如何debug调试jdk源码(任何源码)并显示局部变量
最近要看struts2源码 仿照了一下查看jdk源码的方式 首先你要有strtus2的jar包和源码,在struts官网上下载时,选择full版本,里面会有src也就是源码了. jar导入项目,保证可 ...
- 跟踪调试JDK源码时遇到的问题及解决方法
目录 问题描述 解决思路 在IntelliJ IDEA中调试JDK源码 在eclipse中调试JDK源码 总结 问题描述 最近在研究MyBatis的缓存机制,需要回顾一下HashMap的实现原理.于是 ...
- 随手用python写一个下载jdk源码爬虫
最近在研读jdk源码,网上找了下资源,发现都不完整. 后来新发现了一个有完整源码的地方,主要包括了java,c,c++的东西,装逼需要,就想拿来玩玩.但是,找了好多种下载打开的方式,发现都不对.于是, ...
- 2018-08-27 使用JDT核心库解析JDK源码后初步分析API命名
源自术语词典API项目 · Issue #85 · program-in-chinese/overview, 打算先用早先的代码提取JDK API中的类/方法/参数名, 看看有哪些词需要翻译. 源码在 ...
- JDK源码阅读顺序
很多java开发的小伙伴都会阅读jdk源码,然而确不知道应该从哪读起.以下为小编整理的通常所需阅读的源码范围. 标题为包名,后面序号为优先级1-4,优先级递减 1.java.lang 1) Obj ...
随机推荐
- 000 上传本地库到Github远程库过程全记录
20220613 Github上新创建了一个CsImage库,之后本地创建了一个对应名称的目录,并创建本地库,进行了上传操作,记录一下过程 1.Github上CsImage库创建完成 Github上创 ...
- 五种方式实现 Java 单例模式
前言 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一.这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式. 这种模式涉及到一个单一的类,该类负责创建自 ...
- BUUCTF-RAR
rar 看提示知道爆破压缩包的题,纯数字4位数拿出ARCHPR爆破即可.
- python基础知识-day8(模块与包、random、os)
1.模块与包 package:相同的模块代码存储在一个目录下(即包里边会包含多个模块). 包不能存储在文件夹的目录下,模块名称不能使用关键字.(不包含工程文件夹) 2.模块与包的实例 1)在工程文 ...
- 缤纷多彩的WPF样式框架,开源项目
下面介绍的四种主流样式框架(最近项目需要,所以了解了一些),在Nuget及Github均可以找到~ 首推样式框架MahApp.Metro 再推样式框架ModernUI 三推样式框架MaterialDe ...
- UiPath文本操作Get Visible Text的介绍和使用
一.]Get Visible Text(获取可见文本)操作的介绍 从指示的UI元素中提取字符串及其信息.执行屏幕抓取操作时,还可以自动生成此活动以及容器. 二.Get Visible Text在UiP ...
- 如果一个promise永不resolve,会内存泄漏吗
答:跟内存泄漏没有直接关系gc的策略不会改变,如果该promise没有被人引用,就会被gc掉.如果仍被引用,就不会被gc掉.即使一个promise,resolve或者reject了,但是它还被人引用, ...
- Nginx越界读取缓存漏洞 CVE-2017-7529
1.漏洞描述 Nginx在反向代理站点的时候,通常会将一些文件进行缓存,特别是静态文件.缓存的部分存储在文件中,每个缓存文件包括"文件头"+"HTTP返回包头" ...
- java,捕获和抛出异常
package Exrro; public class Test { //ctrl + alt + T快速生成异常捕捉 public static void main(String[] args) { ...
- Leetcode 1331. 数组序号转换
给你一个整数数组 arr ,请你将数组中的每个元素替换为它们排序后的序号. 序号代表了一个元素有多大.序号编号的规则如下: 序号从 1 开始编号. 一个元素越大,那么序号越大.如果两个元素相等,那么它 ...