相关文章:
https://www.ibm.com/developerworks/cn/java/j-lo-classloader/#download
http://blog.csdn.net/zhoudaxia/article/details/35897057
ClassLoader:类装载器是用来把类(class)装载进JVM的。
在java语言中,是个非常重要的概念。平时我们接触不太多。但是在以下领域我们需要了解ClassLoader的特性:
1、热部署。
2、在类加载阶段,修改字节码,增加特殊功能。(一般用的比较少)
3、jvm通过特定的类加载器实现安全性的要求
JAVA程序对类的使用方式可分为两种:
主动使用
被动使用
所有的Java虚拟机实现必须在每个类或接口被Java程序“首次主动使用”时才初始化他们
主动使用的情况:
1、创建类的实例
2、访问某个类或者接口的静态变量,或者对其进行赋值
3、调用类的静态方法
4、反射
5、初始化一个类的子类(接口不适用)
6、JAVA虚拟机启动时被标明类启动类的类
先了解下关于ClassLoader的基本知识:
1、已经加载的类,不能重复加载,否则会抛出重复加载的异常。为了保证类型安全,必须保证在任何时刻,只要使用相同class loader对象装载同名的类,那么得到的class实例都是相同的。
为了做到这一点,就不能采用系统默认的类加载器委托规则,也就是说我们定制的类加载器在加载时,可以打破规则,自定义加载的顺序,当然这个是要以为功能的需要为目的。
类的加载又分为显式加载和隐式加载。大家使用 new 关键字创建类实例时,其实就隐式地包含了类的加载过程。对于类的显式加载来说,比较常用的是 Class.forName,其实,它们都是通过调用 ClassLoader 类的 loadClass 方法来完成类的实际加载工作的。直接调用 ClassLoader 的 loadClass 方法是另外一种不常用的显式加载类的技术。
2、java是动态加载类的,并且是逐级别的,这样的话,可以节省内存,用到什么加载什么,就是这个道理,然而系统在运行的时候并不知道我们这个应用与需要加载些什么类,那么,就采用这种逐级加载的方式。
(1)首先加载核心API,让系统最基本的运行起来
(2)加载扩展类
(3)加载用户自定义的类
3、一个Class 要想卸载,有一下要求:
1、该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
2、加载该类的ClassLoader已经被GC。
3、该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法
代码验证:
private static void testBasic(){ /** * ouput: null 启动类加载器(Bootstrap ClassLoader) * 这个类加载器负责将<JAVA_HOME>\lib目录下的类库加载到虚拟机内存中 * ,用来加载java的核心库,此类加载器并不继承于java.lang * .ClassLoader,不能被java程序直接调用,代码是使用C++编写的.是虚拟机自身的一部分. */ System.out.println(List.class.getClassLoader()); /** * ouput: sun.misc.Launcher$AppClassLoader@38da9246 * 这个类加载器负责加载用户类路径(CLASSPATH)下的类库,一般我们编写的java类都是由这个类加载器加载, * 这个类加载器是CLassLoader中的getSystemClassLoader * ()方法的返回值,所以也称为系统类加载器.一般情况下这就是系统默认的类加载器. */ System.out.println(ClassLoaderTest.class.getClassLoader()); /** * output:sun.misc.Launcher$ExtClassLoader@15b94ed3 扩展类加载器(ExtendsionClassLoader): * 这个类加载器负责加载<JAVA_HOME>\lib\ext目录下的类库,用来加载java的扩展库, * 开发者可以直接使用这个类加载器. */ System.out.println(DNSNameService.class.getClassLoader()); }
内部class loader:
1、bootstrap class loader --引导类加载器,它负责加载Java的核心类【java.* 】,不是 java.lang.ClassLoader的子类,这个类加载器负责将<JAVA_HOME>\lib目录下的类库加载到虚拟机内存中。
2、extension classloader -扩展类加载器(sun.misc.Launcher$ExtClassLoader@15b94ed3),它负责加载JRE的扩展目录【javax.* 】(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中JAR的类包。
3、system classloader -系统(也称为应用)类加载器(sun.misc.Launcher$AppClassLoader@38da9246
null),它负责加载系统或用户实现的类,在JVM被启动时,加载来自在命令java中的-classpath或者java.class.path系统属性或者 CLASSPATH操作系统属性所指定的JAR类包和类路径,如果没有特别指定,则用户自定义的任何类加载器都将该类加载器作为它的父加载器。ClassLoader.getSystemClassLoader()获取。
4、User Custom ClassLoader/用户自定义类加载器(java.lang.ClassLoader的子类)
在程序运行期间, 通过java.lang.ClassLoader的子类动态加载class文件, 体现java动态实时类装入特性。
ClassLoader加载过程:
classloader 加载类用的是全盘负责委托机制。所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入;委托机制则是先让parent(父)类加载器 (而不是super,它与parent classloader类不是继承关系)寻找,只有在parent找不到的时候才从自己的类路径中去寻找。
ClassLoader 类加载逻辑分析, 以下逻辑是除 BootstrapClassLoader 外的类加载器加载流程:
protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException{ // 检查类是否已被装载过 Class c = findLoadedClass(name); if (c == null ) { // 指定类未被装载过 try { if (parent != null ) { // 如果父类加载器不为空, 则委派给父类加载 c = parent.loadClass(name, false ); } else { // 如果父类加载器为空, 则委派给启动类加载加载 c = findBootstrapClass0(name); } } catch (ClassNotFoundException e) { // 启动类加载器或父类加载器抛出异常后, 当前类加载器将其 // 捕获, 并通过findClass方法, 由自身加载 c = findClass(name); } } }
扩展ClassLoader方法:
1、复写方法 public Class findClass(String name)
2、或者复写public byte [] loadClassData(String name)
ClassLoader的方法说明:
1、findLoadedClass:每个类加载器都维护有自己的一份已加载类名字空间,其中不能出现两个同名的类。凡是通过该类加载器加载的类,无论是直接的还是间接的,都保存在自己的名字空间中,该方法就是在该名字空间中寻找指定的类是否已存在,如果存在就返回给类的引用,否则就返回 null。这里的直接是指,存在于该类加载器的加载路径上并由该加载器完成加载,间接是指,由该类加载器把类的加载工作委托给其他类加载器完成类的实际加载。
2、getSystemClassLoader:Java2 中新增的方法。该方法返回系统使用的 ClassLoader。可以在自己定制的类加载器中通过该方法把一部分工作转交给系统类加载器去处理。
3、defineClass:该方法是 ClassLoader 中非常重要的一个方法,它接收以字节数组表示的类字节码,并把它转换成 Class 实例,该方法转换一个类的同时,会先要求装载该类的父类以及实现的接口类。
4、loadClass:加载类的入口方法,调用该方法完成类的显式加载。通过对该方法的重新实现,我们可以完全控制和管理类的加载过程。
5、resolveClass:链接一个指定的类。这是一个在某些情况下确保类可用的必要方法,详见 Java 语言规范中“执行”一章对该方法的描述。
自定义类加载器初探:
package com.gym.backadmin.controller; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; /** * 自定义类加载器 * @author xinchun.wang @email: 532002108@qq.com * @createTime 2015-4-5 下午7:54:11 */ public class MyClassLoader extends ClassLoader { /** * just a test */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classData = loadClassData(name); return defineClass(classData, 0, classData.length); } private byte[] loadClassData(String urlString) { try { //return byteOutput.toByteArray(); FileInputStream in =new FileInputStream(urlString); ByteArrayOutputStream out = new ByteArrayOutputStream(); FileChannel channel =in.getChannel(); WritableByteChannel outchannel = Channels.newChannel(out); ByteBuffer buffer = ByteBuffer.allocateDirect(1024); while (true) { int i = channel.read(buffer); if (i == 0 || i == -1) { break; } buffer.flip(); outchannel.write(buffer); buffer.clear(); } byte[] bytes =out.toByteArray(); out.close(); in.close(); return bytes; } catch (IOException e) { e.printStackTrace(); } return null; } public static void main(String[] args) throws Exception { MyClassLoader loader = new MyClassLoader(); Class<?> userClass = loader.loadClass("D:\\gym\\haha\\com\\gym\\backadmin\\service\\user\\BasicUserService.class"); Object userService = userClass.newInstance(); Method m = userClass.getMethod("getUser", new Class[]{}); Object result = m.invoke(userService, new Object[]{}); System.out.println(result); } }
运行结果:
{username=ooooooooooooo}
请注意:我把BasicUserService.class 文件放到了一个随意的目录。然后去加载二进制文件的。
/** * * @author xinchun.wang @email: 532002108@qq.com */ public class BasicUserService implements UserService { public Map<String, Object> getUser() { Map<String, Object> model = new HashMap<String, Object>(); model.put("username", "ooooooooooooo"); return model; } }
另外:Object userService = userClass.newInstance();
如果改为:BasicUserService userService = (BasicUserService)userClass.newInstance();
会出现:
原因如下:
因为在 Java 中,即使是同一个类文件,如果是由不同的类加载器实例加载的,那么它们的类型是不相同的。在上面的例子中 userClass 是由 MyClassLoader 加载的,而 userService 变量类型声名和转型里的 BasicUserService 类却是由 run 方法所属的类的加载器(默认为 AppClassLoader)加载的,因此是完全不同的类型,所以会抛出转型异常。
特别注意:对于接口:
1、初始化一个类并不会先初始化它所实现的接口。
2、初始化一个接口时,并不会先初始化它的父接口。
/** * @author xinchun.wang @email: 532002108@qq.com * @createTime 2015-4-7 上午10:58:57 */ public class ImplementsTest { public static void main(String[] args) { A a2 = new A2(); System.out.println(a2); // 注意A没有被初始化 System.out.println(a2.a); //才会对A接口进行初始化,可以注释掉本行 做测试 } static interface A { public static final A a = new A1(); } static class A1 implements A { static { System.out.println("hello world in A"); } } static class A2 implements A { } }
相关推荐
主要内容包括 Java类加载机制及加载流程,以及如何定义自己的类加载器,如何实现类的热替换。
本篇文章主要给大家讲述了Java中ClassLoader类加载的原理以及用法总结,一起学习下。
主要介绍了Java类加载器ClassLoader用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
其实JDK的学习没有那么简单,关于JDK有两个问题是很容易一直困扰Java程序员的地方:一个是CLASSPATH的问题,其实从原理上来说,是要搞清楚JRE的ClassLoader是如何加载Class的;另一个问题是package和import问题,...
java jdk源码学习 ...ClassLoader 4 Compiler 4 System 4 Package 4 Void 4 java.util AbstractList 1 AbstractMap 1 AbstractSet 1 ArrayList 1 LinkedList 1 HashMap 1 Hashtable 1 HashSet 1 LinkedHashMa
深入Java虚拟机JVM类加载学习笔记:jvm java classloader 垃圾回收 gc
主要给大家介绍了关于Java运行时环境之ClassLoader类加载机制的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
针对Java ClassLoaders的学习文章,让你全面掌握classloader的特性
框架开发学习 此仓库给出了在框架开发中经常使用的不同Java概念和编程技术的示例。 例如,当我们想从头开始创建RPC框架时,我们需要了解Java动态代理和序列化。 这是清单: 技术 模块/链接 设想 地位 评论 动态...
java ClassLoader的学习 java是一门解释执行的语言,由开发人员编写好的java源文件先编译成字节码文件.class形式,然后由java虚拟机(JVM)解释执行,.class字节码文件本身是平台无关的,但是jvm却不是,为了实现...
面试题集共分为以下十部分: 一、Core Java: 1 — 95 题1 — 24 页 基础及语法: 1 — 61 题1 — 13 页 异常: 62 — 69 题13 — 15 页 集合: 70 — 80 题15 — 18 页 线程: 81 — 90 题18 — 21 页 ...
15.2.2 建立classloader实例 518 15.3 重点复习 520 15.4 课后练习 521 chapter16 自定义泛型、枚举与标注 523 16.1 自定义泛型 524 16.1.1 定义泛型方法 524 16.1.2 使用extends与? 525 16.1.3 使用...
作者与学习乐园原始码地址:我的作者:项目结构src目录Java虚拟机核心知识点学习代码并测试案例test目录(测试包名与src目录保持一致)对应学习代码包的详细测试案例包目录: ├── org.jvmcore.classloader// 类...
太原理工大学机器人团队20天学习打卡day2 学习内容:Java 学习网站:b站 day02 今天的内容比昨天多很多,也更难理解,希望能坚持下去 1、打开DOS命令窗口,执行java HelloWorld,执行原理 java.exe命令会启动JVM JVM...
部分主要阐述Thread的基础知识,详细介绍线程的API使用、线程安全、线程间数据通信,以及如何保护共享资源等内容,它是深入学习多线程内容的基础。 第二部分引入了ClassLoader,这是因为ClassLoader与线程不无关系,...
插件化代码的编写,涉及到的知识点主要有java中的反射,动态代理,静态代理以及android中的AIDL跨进程通信,binder机制,ClassLoader加载机制,四大组件的运行原理等等。本项目代码主要参考和。在此基础上做了大量的...
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...
java的测试项目,可以看做是java的ApiDemo,主要用于学习,也经常用来测试极光,七牛等服务器api, 实际上有什么好代码都可以加进来,直到这个工程不堪其重 目录: 目录 [java高级] [Ayo库] 集合 ConcurrentMap原理...
Java8源码学习 ├── com/ ├── java/(常用代码都在此文件夹下) │ ├── lang/ │ │ ├── ClassLoader │ │ ├── Enum │ │ ├── Integer │ │ ├── Long │ │ ├── String │ │ ├── ...