浅淡java类加载机制

本人学java出身,但说起来惭愧,对java的底层却不是很了解,比方说一会儿要淡到的类加载机制。

大家在运行java程序的时候有没有想过,这个程序是怎么运行的。也许有得朋友会说,先编译成字节码,然后再加载到内存运行。不错,确实是这样,那新问题又来了,到底是怎么加载的。这里就会涉及到java的类加载机制。

理解类加载机制,可以在程序运行的过程中动态的加载相应的类,从而提高程序的灵活性和适应性。

一个程序HelloWorld.java,它需要运行,并不是简简单单地将其字节码加载到内存就完事儿了,它需要jdk和jre的支持。这就像盖楼一样,没有下面的地基,这个楼就无法完成。所以在加载HelloWorld.class之前,要将jdk和jre加载到内存。那么怎么加?这里就使用了所谓的加载器(classloader)。说到这里,不知道大家有没有注意,我们需要加载 jdk, jre, HelloWorld.class, 这三者的加载需要使用一个加载器行不行?答案:不行。因为这三者的级别不一样,所以需要使用不同的加载器。首先,jdk 是java的核心内库,也就是说它是最底层的,所以加载他的时候需要一个能跟底层打交道的加载器,这里jvm提供了bootstrap class loader(它是由c编写的,其他的加载器都是用java写的)。其次,jre是jdk的扩展类库,jvm提供了 extension class loader。最后,jvm提供了application class loader, 专门用来加载用户定义的类,例如HelloWorld。

整个加载顺序也如前言描述一样,bootstrap class loader, extension class loader, application class loader。首先一上来bootstrap class loader 就加载其他的classloader, 有了这些classloader后面的load工作就按序进行了。在这里,每一个classloader都持有上一层classloader的引用,所以classloader之间不是继承关系,而是关联的关系。在加载过程中,classloader首先找上一层loader是不是加载过了,如果已经加载过了,就不会再次load。这样就保证了安全性,例如自己写的String永远就没有机会被加载,因为上层加载过了。另外,每一种classloader只负责自己管辖范围的类。除此之外,还有其他的加载器,在这里就不详细列出了。

这里引用了别人的一个例子:

public class HelloWorld { 
        public static void main(String[] args) { 
                HelloWorld hello = new HelloWorld(); 
                Class c = hello.getClass(); 
                ClassLoader loader = c.getClassLoader(); 
                System.out.println(loader); 
                System.out.println(loader.getParent()); 
                System.out.println(loader.getParent().getParent()); 
        } 
}
 
打印结果:
sun.misc.Launcher$AppClassLoader@19821f 
sun.misc.Launcher$ExtClassLoader@addbf1 
null 

Process finished with exit code 0
 
从上面的结果可以看出,并没有获取到ExtClassLoader的上层Loader,原因是Bootstrap Loader(启动类加载器)是用C语言实现的,找不到一个确定的返回上层Loader的方式,于是就返回null。

猜你喜欢

转载自blog.csdn.net/hongyinanhai00/article/details/48732621