系列文章目录
前言
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。
Java程序在运行的时候,JVM通过类加载机制(ClassLoader)把class文件加载到内存中,只有class文件被载入内存,才能被其他class引用,使程序正确运行起来.
Java中的ClassLoader有三种:Bootstrap ClassLoader 、Extension ClassLoader、App ClassLoader。
- 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
如果想要保护你的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