托了好久,终于开始JAVA File 的分析,废话不说,还是先上代码
public class File
implements Serializable, Comparable<File>
{
static private FileSystem fs = FileSystem.getFileSystem();
File 想发挥作用,就要先获取文件系统,跟进FileSystem.getFileSystem(); 看看
abstract class FileSystem {
/**
* Return the FileSystem object representing this platform's local
* filesystem.
*/
public static native FileSystem getFileSystem();
是个native方法,通过JNI找到FileSystem_md.c
#include "jni.h"
#include "jni_util.h"
#include "java_io_FileSystem.h"
JNIEXPORT jobject JNICALL
Java_java_io_FileSystem_getFileSystem(JNIEnv *env, jclass ignored)
{
return JNU_NewObjectByName(env, "java/io/UnixFileSystem", "()V");
}
看到getFileSystem了吧
继续跟进入JNU_NewObjectByName函数
JNIEXPORT jobject JNICALL
JNU_NewObjectByName(JNIEnv *env, const char *class_name,
const char *constructor_sig, ...)
{
jobject obj = NULL;
jclass cls = 0;
jmethodID cls_initMID;
va_list args;
if ((*env)->EnsureLocalCapacity(env, 2) < 0)
goto done;
cls = (*env)->FindClass(env, class_name);
if (cls == 0) {
goto done;
}
cls_initMID = (*env)->GetMethodID(env, cls,
"<init>", constructor_sig);
if (cls_initMID == NULL) {
goto done;
}
va_start(args, constructor_sig);
obj = (*env)->NewObjectV(env, cls, cls_initMID, args);
va_end(args);
done:
(*env)->DeleteLocalRef(env, cls);
return obj;
}
代码就不跟了,有兴趣的同学自己跟吧,这个处理过程就是要通过传入的参数(类的路径和类名)生成类的实例。unix系统中 返回UnixFileSystem.java 类的实例,上面代码传入了“java/io/UnixFileSystem”,也就是生成UnixFileSystem的实现,也正是我们要研究的。
在这里多说一句,大家可以根据上面的代码,就能跟出一个java类的在虚拟机中实例创建过程
cls = (*env)->FindClass(env, class_name);
以上代码,在方法区,也就是永久区,找到了该要实例的类(注意是类,不是对象,对象是在堆区,实例的类指的是该类是否被虚拟机的类加载器加载)
cls_initMID = (*env)->GetMethodID(env, cls,
"<init>", constructor_sig);
以上代码,获取方法区标识
va_start(args, constructor_sig);
obj = (*env)->NewObjectV(env, cls, cls_initMID, args);
va_end(args);
以上代码,实例化类,创建类的实例---对象
这里仅仅是一个流程,并没有进去方法内,其实现过程是相当复杂的。还是不多讲了。
接着说这个被实例化的类,我还是可耻的上代码啦
package java.io;
import java.security.AccessController;
import sun.security.action.GetPropertyAction;
class UnixFileSystem extends FileSystem {
private final char slash;
private final char colon;
private final String javaHome;
public UnixFileSystem() {
slash = AccessController.doPrivileged(
new GetPropertyAction("file.separator")).charAt(0);
colon = AccessController.doPrivileged(
new GetPropertyAction("path.separator")).charAt(0);
javaHome = AccessController.doPrivileged(
new GetPropertyAction("java.home"));
}
public char getSeparator() {
return slash;
}
public char getPathSeparator() {
return colon;
}
/* A normal Unix pathname contains no duplicate slashes and does not end
with a slash. It may be the empty string. */
/* Normalize the given pathname, whose length is len, starting at the given
offset; everything before this offset is already normal. */
private String normalize(String pathname, int len, int off) {
if (len == 0) return pathname;
int n = len;
while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
if (n == 0) return "/";
StringBuffer sb = new StringBuffer(pathname.length());
if (off > 0) sb.append(pathname.substring(0, off));
char prevChar = 0;
for (int i = off; i < n; i++) {
char c = pathname.charAt(i);
if ((prevChar == '/') && (c == '/')) continue;
sb.append(c);
prevChar = c;
}
return sb.toString();
}
public String normalize(String pathname) {
int n = pathname.length();
char prevChar = 0;
for (int i = 0; i < n; i++) {
char c = pathname.charAt(i);
if ((prevChar == '/') && (c == '/'))
return normalize(pathname, n, i - 1);
prevChar = c;
}
if (prevChar == '/') return normalize(pathname, n, n - 1);
return pathname;
}
public int prefixLength(String pathname) {
if (pathname.length() == 0) return 0;
return (pathname.charAt(0) == '/') ? 1 : 0;
}
public String resolve(String parent, String child) {
if (child.equals("")) return parent;
if (child.charAt(0) ==