getClassLoader能否为null

2022-08-24 20:45:48 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

前言

我们Javaer都知道类想要被加载是需要一个个ClassLoader来执行的,并且类加载的方案叫双亲委派模式,说是双亲,其实就是单亲,可能我们最初的翻译人想让我们的加载器的家庭更完整吧,所以翻译成双亲。默认的类加载器包括BootstrapClassLoader、ExtClassLoader、AppClassLoader,他们都定义在在rt.jar中的sun.misc.Launcher类中,他们的”继承”关系是AppClassLoader—>ExtClassLoader—>BootstrapClassLoader,ExtClassLoader的parent获取不到BootstrapClassLoader,只能获取到一个null。

  1. bootstrap是C 编写的类加载器,主要加载%JRE_HOME/lib/目录下的jar包
  2. ExtClassLoader主要加载%JRE_HOME/lib/ext目录下的jar包
  3. AppClassLoader主要加载java环境变量CLASSPATH所指定的路径下的jar包和class文件,通过System.getProperty(“java.class.path”)获取考验获取CLASSPATH路径
  4. 用户自定义ClassLoader,加载用户自己制定的类

getClassLoader会不会为空

说了这么多,其实就是想说getClassLoader当然可能会为空,是不是此时会有个疑惑:加载器都为空了,那这个类是怎么加载的,被谁加载的?答:被BootstrapClassLoader加载的。

我们知道BootstrapClassLoader是由C 编写的,我们是用Java代码获取不到的,BootstrapClassLoader也不是ExtClassLoader的父类,而是它的父亲,这里要搞清关系,父亲和父类是两码事,父类是有继承关系,父亲是上一层的关系,所以我们在获取String、Integer、int、double、BufferedInputStream等等一系列在rt.jar包中被BootstrapClassLoader加载的类的加载器时,返回的都是null。

ExtClassLoader是怎么成为AppClassLoader的父亲的

类加载器并非是继承关系,而是父子关系,就像上面说的BootstrapClassLoader是ExtClassLoader的父亲,不是父类。关键点就在于ClassLoader的实例变量parent,这个parent指定了当前类加载器的父亲,但是翻遍了AppClassLoader的代码也没发现是在哪里把ExtClassLoader设置进去的,怎么parent就是ExtClassLoader了呢。

刚才我们说这些类加载器被定义在了Launcher类中,那么我们就去看下这个类的构造器

代码语言:javascript复制
public Launcher() {
  Launcher.ExtClassLoader var1;
  try {
    // 获取ExtClassLoader
    var1 = Launcher.ExtClassLoader.getExtClassLoader();
  } catch (IOException var10) {
    throw new InternalError("Could not create extension class loader", var10);
  }

  try {
    // 获取AppClassLoader实例并赋值给loader,并把ExtClassLoader的实例传入到方法中,
    this.loader = Launcher.AppClassLoader.getAppClassLoader(var1);
  } catch (IOException var9) {
    throw new InternalError("Could not create application class loader", var9);
  }
  // ...
}
// 返回AppClassLoader实例
public ClassLoader getClassLoader() {
  return this.loader;
}

从Launcher的构造器我们看到关键点在AppClassLoader.getAppClassLoader(var1)这句,那我们就看这个方法是怎么写的

代码语言:javascript复制
static class AppClassLoader extends URLClassLoader {
  public static ClassLoader getAppClassLoader(final ClassLoader var0) throws IOException {
    final String var1 = System.getProperty("java.class.path");
    final File[] var2 = var1 == null ? new File[0] : Launcher.getClassPath(var1);
    return (ClassLoader)AccessController.doPrivileged(new PrivilegedAction<Launcher.AppClassLoader>() {
      public Launcher.AppClassLoader run() {
        URL[] var1x = var1 == null ? new URL[0] : Launcher.pathToURLs(var2);
        // 关键看这一句,调用了AppClassLoader的构造器,并把ExtClassLoader实例传了进去,那就跳到构造器去看
        return new Launcher.AppClassLoader(var1x, var0);
      }
    });
  }

  // 构造器
  AppClassLoader(URL[] var1, ClassLoader var2) {
    // 调用了父类的构造器,他的父类是哪个?从定义上看应该是URLClassLoader没跑了
    super(var1, var2, Launcher.factory);
    this.ucp.initLookupCache(this);
  }
}

其实再往里的代码就不用在这闲扯了,里面就是不断的将var2往上传递,直到ClassLoader这个类的构造器中,在ClassLoader中完成的设置。

那为什么ExtClassLoader没通过这种形式将BootstrapClassLoader设置给parent呢?

是不是傻,上面刚说了BootstrapClassLoader是C 写的,Java代码不能直观的获取。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/141668.html原文链接:https://javaforall.cn

0 人点赞