1、ClassLoader类加载器
系统的环境变量CLASSPATH的主要作用是在JVM启动的时候进行类加载路径的定义。在JVM中可根据类加载器进行指定路径中类的加载,即找到类加载器就找到了类的来源。而类加载器通过ClassLoader类来获得,要想获得ClassLoader类对象则需使用Class类(反射的根源)来实现。方法:public ClassLoader getClassLoader(),进一步可以获取其父类ClassLoader类对象:public final ClassLoader getParent()
使用示例:
public class CDemo {
public static void main(String[] args) throws Exception {
Class<?> clazz = CDemo.class ;
System.out.println(clazz.getClassLoader()) ; //获取当前类的加载器
System.out.println(clazz.getClassLoader().getParent()) ;
System.out.println(clazz.getClassLoader().getParent().getParent()) ;
}
}
运行结果:
AppClassLoader应用程序加载器;
PlatformClassLoader平台类加载器(JDK1.8及以前为扩展类加载器ExtClassLoader,该类存在不安全问题,所以被废除不再使用);
还有一个无法看见的系统类加载器Bootstrap;
当获得类加载器后就可以利用类加载器来实现类的反射加载处理。
2、自定义ClassLoader处理类
类加载器的加载先后顺序:Bootstrap→PlatformClassLoader→AppClassLoader→自定义类加载器
系统类中的类加载器都是根据CLASSPATH路径进行类加载的,而自定义的类加载器,就可以由开发者任意指派类的加载位置。
示例:
D盘下程序文件:
package com.demo ;
public class CDemo {
public void send() {
System.out.println("一只瓶子a") ;
}
}
自定义类加载器:
package com.demo1;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
public class TimerDemo {
public static void main(String[] args) throws Exception {
newClassLoader classLoader = new newClassLoader() ; //实例化自定义类加载器
Class<?> cls = classLoader.loadData("com.demo.CDemo") ;
Object obj = cls.getDeclaredConstructor().newInstance() ; //根据构造方法实例化类对象
Method method = cls.getDeclaredMethod("send") ;
method.invoke(obj) ;
}
}
class newClassLoader extends ClassLoader {
private static final String DEMO_CLASS_PATH = "D:" + File.separator + "CDemo.class" ;
/**
* 进行指定类的加载
* @param className 类的完整名称“包.类”
* @return 返回一个指定类的Class对象
* @throws Exception 如果类文件不存在则无法加载
*/
public Class<?> loadData(String className) throws Exception {
byte [] data = this.loadClassData() ; //读取二进制文件
if(data != null) {
return super.defineClass(className, data, 0, data.length) ;
}
return null ;
}
public byte [] loadClassData() throws Exception { //通过文件进行类的加载
InputStream input = null ;
ByteArrayOutputStream bos = null ; //将数据加载到内存中
byte data [] = null ;
try {
bos = new ByteArrayOutputStream() ; //实例化内存流
input = new FileInputStream(new File(DEMO_CLASS_PATH)) ; //文件流加载
input.transferTo(bos) ; //读取数据
data = bos.toByteArray() ;
}catch(Exception e) {
e.printStackTrace();
}finally {
if(input != null) {
input.close();
}
if(bos != null) {
bos.close();
}
}
return data ;
}
}
结合日后的网络程序开发,就可以通过一个远程的服务器来确定类的功能。
如果要加载的程序类是由系统提供的类则会由系统类进行加载,如果开发者定义的类与系统类名称相同,那么为了保证系统的安全其不会被加载。