Java程序在运行的时候,JVM通过类加载机制(ClassLoader)把class文件加载到内存中,只有class文件被载入内存,才能被其他class引用,使程序正确运行起来.
Java中的ClassLoader有三种:Bootstrap ClassLoader 、Extension ClassLoader、App ClassLoader。
1. Bootstrap ClassLoader
由C++写的,由JVM启动.
启动类加载器,负责加载java基础类,对应的文件是%JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
2.Extension ClassLoader
Java类,继承自URLClassLoader 扩展类加载器,
对应的文件是 %JRE_HOME/lib/ext 目录下的jar和class等
3.App ClassLoader
Java类,继承自URLClassLoader 系统类加载器,
对应的文件是应用程序classpath目录下的所有jar和class等
Java的加载机制是双亲委派机制来加载类
为什么要使用这种方式?这个是为了保证 如果加载的类是一个系统类,那么会优先由Bootstrap ClassLoader 、Extension ClassLoader先去加载,而不是使用我们自定义的ClassLoader去加载,保证系统的安全!
系统的ClassLoader只会加载指定目录下的class文件,如果你想加载自己的class文件,那么就可以自定义一个ClassLoader。
新建一个类继承自java.lang.ClassLoader,重写它的findClass方法,然后将class字节码数组转换为Class类的实例,调用loadClass方法即可。
新建一个样品Java文件,并生成class,然后拷贝到指定目录
package com.javacui.test; public class ClassLoaderTest { public static void main(String[] args) { System.out.println("I am ClassLoaderTest"); for (String str : args){ System.out.println("参数:" + str); } } }
自定义一个类加载器,加载该class文件并调用main方法
import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.lang.reflect.Method; public class MyClassLoader extends ClassLoader { public static void main(String[] args) throws Exception { //这个类class的路径 String classPath = "D://temp/ClassLoaderTest.class"; //类的全称,有包名的加包名 String packageNamePath = "com.javacui.test.ClassLoaderTest"; MyClassLoader myClassLoader = new MyClassLoader(classPath); //加载ClassLoaderTest类的class文件 Class<?> myclass = myClassLoader.loadClass(packageNamePath); System.out.println("类加载器是:" + myclass.getClassLoader()); //利用反射获取main方法 Method method = myclass.getDeclaredMethod("main", String[].class); Object object = myclass.newInstance(); String[] arg = {"java小强", "博客"}; method.invoke(object, (Object) arg); } //指定路径 private String path; public MyClassLoader(String classPath) { path = classPath; } /** * 重写findClass方法 * * @param name 是我们这个类的全路径 * @throws ClassNotFoundException */ @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class myclass = null; // 获取该class文件字节码数组 byte[] classData = getData(); if (classData != null) { // 将class的字节码数组转换成Class类的实例 myclass = defineClass(name, classData, 0, classData.length); } return myclass; } /** * 将class文件转化为字节码数组 */ private byte[] getData() { File file = new File(path); if (file.exists()) { FileInputStream in = null; ByteArrayOutputStream out = null; try { in = new FileInputStream(file); out = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int size = 0; while ((size = in.read(buffer)) != -1) { out.write(buffer, 0, size); } } catch (IOException e) { e.printStackTrace(); } finally { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } return out.toByteArray(); } else { return null; } } }
输出
类加载器是:sun.misc.Launcher$AppClassLoader@14dad5dc I am ClassLoaderTest 参数:java小强 参数:博客
如果想要保护你的class文件,那可以借助自定义类加载器,因为java的class文件是可以被轻易反编译的。
例如上面,我们生成class文件后,可以通过对称加密等方式进行加密,那么拿到的class字节都是加密后,是无法使用的,在上面的getData()方法中我们读取到了文件字节流,可以把该字节流再进行解密。
DES加密使用入门 http://www.javacui.com/java/17.html
JAVA加密算法实现用例 密钥一致协议 http://www.javacui.com/Theory/273.html
JAVA加密算法实现用例 数字签名 http://www.javacui.com/java/312.html
推荐您阅读更多有关于“ extension Bootstrap 类加载器 ClassLoader URLClassLoader ”的文章
Java小强
未曾清贫难成人,不经打击老天真。
自古英雄出炼狱,从来富贵入凡尘。
发表评论: