阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第25章:ClassLoader类加载器:课时116:自定义ClassLoader处理类
程序员文章站
2022-07-04 18:51:10
...
清楚了类加载器的功能之后就可以根据自身的需要来实现自定义的类加载器,但是需要千万要记住一点,自定义的类加载器其加载的顺序是所有系统类加载器的最后。系统类中的类加载器都是根据CLASSPATH路径进行类加载的,而如果有了自定义类的加载器,就可以由开发者任意指派类的加载位置。
1、随意编写一个程序类,并且将这个类保存在磁盘上。
package cn.mldn.util;
public class Message {
public void send() {
System.out.println("www.mldn.cn");
}
}
2、将此类直接拷贝到D盘上进行编译处理,并且不打包:javac Message.java,此时并没有进行打包处理,所以这个类无法通过CLASSPATH正常加载。
3、自定义一个类加载器,并且继承自ClassLoader类。在ClassLoader类里面为用户提供有一个字节转换为类结构的方法:
定义类:protected final Class<?> defineClass(String name, byte[] b, int off, int len) thorws ClassFormatError;
package cn.mldn.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
public class MLDNClassLoader extends ClassLoader {
private static final String MESSAGE_CLASS_PATH = "D:" + File.separator + "Message.class";
/**
* 进行指定类的加载
* @param className 类的完整名称“包.类”
* @return 返回一个指定类的Class对象
* @throws Exception 如果类文件不存在则无法加载
*/
public Class<?> loadData(String className) throws Exception {
byte [] data = this.loadClassDate(); // 读取二进制数据文件
if (data != null) { // 读取到了
return super.defineClass(className, data, 0, data.length) ;
}
return null ;
}
private byte [] loadClassDate() throws Exception { // 通过文件进行类的加载
InputStream input = null ;
ByteArrayOutputStream bos = null ; // 将数据加载到内存之中
byte data [] = null ;
try {
bos = new ByteArrayOutputStream() ; // 实例化内存流
input = new FileInputStream(new File(MESSAGE_CLASS_PATH)); // 文件流加载
input.transferTo(bos); // 读取数据
data = bos.toByteArray(); // 将所以读取到的字节数据取出
} catch (Exception e) {
} finally {
if (input != null) {
input.close();
}
if (bos != null) {
bos.close();
}
}
return data;
}
}
4、编写测试类实现类加载控制。
package cn.mldn.demo;
import java.lang.reflect.Method;
import cn.mldn.util.MLDNClassLoader;
class Message {}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
MLDNClassLoader classLoader = new MLDNClassLoader(); // 实例化自定义加载器
Class<?> cls = classLoader.loadData("cn.mldn.util.Message"); // 进行类的加载
Object obj = cls.getDeclaredConstructor().newInstance();
Method method = cls.getDeclaredMethod("send");
method.invoke(obj);
}
}
如果在以后结合到网络程序开发的话,就可以通过一个远程的服务器来确定类的功能。
5、观察当前的Message类的加载器的情况。
package cn.mldn.demo;
import cn.mldn.util.MLDNClassLoader;
class Message {}
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
MLDNClassLoader classLoader = new MLDNClassLoader(); // 实例化自定义加载器
Class<?> cls = classLoader.loadData("cn.mldn.util.Message"); // 进行类的加载
System.out.println(cls.getClassLoader());
System.out.println(cls.getClassLoader().getParent());
System.out.println(cls.getClassLoader().getParent().getParent());
}
}
程序执行结果:
cn.mldn.util.MLDNClassLoader@312b1dae
jdk.internal.loader.ClassLoaders$AppClassLoader@119d7047
jdk.internal.loader.ClassLoaders$PlatformClassLoader@3941a79c
如果说你现在定义了一个类,这个类的名字为:java.lang.String,并且利用了自定义的类加载进行加载处理,这个类将不会被加载,java之中针对于类加载器提供有双亲加载机制,如果现在要加载的程序类是由系统提供的类则会由系统类进行加载,如果现在开发者定义的类与系统类名称相同,那么为了保证系统的安全性绝对不会加载。
推荐阅读
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第24章:反射与简单Java类:课时111:单级属性赋值
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第23章:反射与类操作:课时105:反射调用构造方法(含关系图-重要)
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第25章:ClassLoader类加载器:课时115:ClassLoader类加载器简介
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第12章:开发支持类库:课时49:ThreadLocal类
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第33章:集合工具类:课时149:Collections工具类
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第12章:开发支持类库:课时50:定时调度
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第1章:Java多线程编程:课时3:Thread类实现多线程
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第24章:反射与简单Java类:课时110:属性自动赋值实现思路
-
阿里Java学习路线:阶段 1:Java语言基础-Java语言高级特性:第25章:ClassLoader类加载器:课时116:自定义ClassLoader处理类
-
Java语言基础-Java语言高级特性:ClassLoader类加载器;自定义ClassLoader处理类