设为首页 加入收藏

TOP

关于Class对象、类加载机制、虚拟机运行时的内存布局的全面解析和推测(一)
2017-10-10 12:31:24 】 浏览:8253
Tags:关于 Class 对象 加载 机制 虚拟 行时 内存 布局 全面 解析 推测

简介:

本文是对Java的类加载机制,Class对象,反射原理等相关概念的理解、验证和Java虚拟机中内存布局的一些推测。本文重点讲述了如何理解Class对象以及Class对象的作用。

欢迎探讨,如有错误敬请指正

如需转载,请注明出处 http://www.cnblogs.com/nullzx/


1. 类加载机制

当我们编写好一个“.java”文件,通过javac编译器编译后会形成一个“.class”文件。当我们运行该文件时,Java虚拟机就通过类加载器(类加载器本质就是一段程序)把“.class”文件加载到内存,在方法区形成该类各方法的代码段和描述该类细节信息的常量池,同时在堆区形成一个表示该类的Class对象(java.lang.Class类的实例)。Class对象中存储了指向了该类的属性和方法的所有详细信息的指针(同时,还存储了指向该类的父类的Class对象的指针)。我们能够通过Class对象直接创建该类的实例,并调用该类的所有方法,这就是我们所说的反射。

类加载器不仅仅可以加载本地文件系统中的“.class”文件,还可以通过各种形式进行加载,比如通过网络上的获取的数据流作为 “.class”。

类加载器本质上是实现一个解析的工作,把表示该类的字节数据变成方法区中的字节码和并在堆区产生表示该类的Class对象。

 

1.1 类加载器(ClassLoader)的层次结构

Java默认提供的三个ClassLoader(JAVA_HOME表示JDK的安装目录)

BootStrapClassLoader:称为启动类加载器,是Java类加载层次中最顶层的类加载器,负责加载JAVA_HOME\jre\lib目录下JDK中的核心类库,如:rt.jar、resources.jar、charsets.jar等。该加载器不是ClassLoader的子类,由C/C++语言实现其功能。

ExtensionClassLoader:称为扩展类加载器,负责加载Java的扩展类库,默认加载JAVA_HOME\jre\lib\ext目下的所有jar。它是ClassLoader的子类,由Java语言实现。

AppClassLoader:称为应用程序类加载器,负责加载当前应用程序目录下的所有jar和class文件以及环境变量CLASSPATH指定的jar(即JAVA_HOME/lib/dt.jar和JAVA_HOME/lib/tools.jar)和第三方jar。AppClassLoader是ClassLoader的子类,由Java语言实现。

注意JDK中有两个lib目录,一个是JAVA_HOME/lib,另一个是JAVA_HOME/jre/lib。

在java中,还存在两个概念,分别是系统类加载器和线程上下文类加载器,其实都是指是AppClassLoader加载器。

 

1.2 类加载器双亲委派模型

ClassLoader使用的是双亲委托来搜索类的。每个ClassLoader实例都有一个父类加载器的引用(不是继承的关系,是一个包含的关系)。

AppClassLoader的父加载器是ExtensionClassLoader,而Extension ClassLoader的父加载器是BootstrapClassLoader,而Bootstrap ClassLoader是虚拟机内置的类加载器,本身没有父加载器。

image

(图片来自于http://blog.csdn.net/u011080472/article/details/51332866

当一个ClassLoader对象需要加载某个类时,在它试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,父类加载器继续向上委托,直到BootstrapClassLoader类加载器为止。即,首先由最顶层的类加载器BootstrapClassLoader在指定目录试图加载目标类,如果没加载到,则把任务回退给ExtensionClassLoader,让它在指定目录进行加载,如果它也没加载到,则继续回退给App ClassLoader 进行加载,以此类推。如果所有的加载器都没有找到该类,则抛出ClassNotFoundException异常。否则将这个找到的“*.class”文件进行解析,最后返回表示该类的Class对象。

java代码中我们只能使用ExtensionClassLoader和AppClassLoader的实例,这两种类加载器分别有且只有一个实例。我们无法通过任何方法创建这两个类的额外的实例,可以理解为设计模式中的单例模式。

 

1.3 为什么要使用双亲委托这种模型呢?

1)这样可以避免重复加载,当父亲已经加载了该类的时候,就没有必要子加载器再加载一次。

2)核心类通过Java自带的加载器加载,可以确保这些类的字节码没有被篡改,保证代码的安全性。

JVM在判定两个Class对象是否相同时,不仅要满足两个类名相同,而且要满足由同一个类加载器加载。只有两者同时满足的情况下,JVM才认为这两个Class对象是相同的。

 

1.4 自定义类加载器

除了Java默认提供的三个类加载器之外,用户还可以根据需要定义自已的类加载器,自定义的类加载器都必须继承自java.lang.ClassLoader类。

 

既然JVM已经提供了默认的类加载器,为什么还要定义自已的类加载器呢?

1)因为Java中提供的默认ClassLoader,只加载指定目录下的jar和class,如果我们想加载其它位置的class文件或jar时就需要定义自己的ClassLoader。

2)对于那些已经加密过的Class文件,自定义ClassLoader可以在解析Class文件前,进行解密操作。这样相互配合的方式保证了代码的安全性。

 

1.5 定义自已的类加载器的步骤

主要分为两步

1)继承java.lang.ClassLoader

2)重写父类的findClass方法

下面是API文档中给出的自定义加载器的实现模型

     class NetworkClassLoader extends ClassLoader {
         String host;
         int port;

         public Class findClass(String name) {
             byte[] b = loadClassData(name);
             return defineClass(name, b, 0, b.length);
         }

         private byte[] loadClassData(String name) {
             // load the class data from the connection
              . . .
         }
     }

 

下面的代码是一个类加载器的具体实现。MyClassLoader类加载器主要加载任意指定目录下的“*.class”文件,而这个指定的目录又不在环境变量ClassPath所表示的目录中。

 

package demo;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
im
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇设计模式精要 下一篇没有了

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目