JVM类加载器与自定义类加载器

JVM内置的三大类加载器

JVM提供了三大类加载器,不同的加载器负责将不同的类加载到JVM内存中,并且它们之间严格遵守父委托机制。
根类加载器
根加载器又称Bootstrap类加载器,是最顶层的加载器由C++编写,主要负责虚拟机核心库的加载,比如java.lang包都是根加载加载的,根加载器的加载路径可以通过“sun.boot.class.path”获取。

	public static void main(String[] args) {
		System.out.println(System.getProperty("sun.boot.class.path"));
	}

输出
C:\Program Files\Java\jre1.8.0_221\lib\resources.jar;
C:\Program Files\Java\jre1.8.0_221\lib\rt.jar;
C:\Program Files\Java\jre1.8.0_221\lib\sunrsasign.jar;
C:\Program Files\Java\jre1.8.0_221\lib\jsse.jar;
C:\Program Files\Java\jre1.8.0_221\lib\jce.jar;
C:\Program Files\Java\jre1.8.0_221\lib\charsets.jar;
C:\Program Files\Java\jre1.8.0_221\lib\jfr.jar;
C:\Program Files\Java\jre1.8.0_221\classes

扩展类加载器
扩展类加载器的父加载器时根加载器,主要用于加载JAVA_HOME下的jre\lb\ext子目录里的类库,由java语言编写,是java.lang.URLClassLoader的子类,加载路径可以通过“java.ext.dirs”获取。

	public static void main(String[] args) {
		System.out.println(System.getProperty("java.ext.dirs"));
	}

输出
C:\Program Files\Java\jre1.8.0_221\lib\ext;
C:\WINDOWS\Sun\Java\lib\ext

系统类加载器
负责加载classpath下的类库资源,父加载器时扩展类加载器,同时也是我们自定义的类加载器的默认父加载器,加载路径可以通过“java.class.path”获取。

自定义类加载器

所有的自定义类加载器都是ClassLoader的直接子类或者间接子类,java.lang.ClassLoader是一个抽象类,里面没有抽象方法,但是有findClass方法,务必实现该方法,否则会抛出Class找不到异常。

自定义类加载器代码

package com.pys.classloader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

public class MyClassLoader extends ClassLoader{
	//默认的class存放路径
	 private final static Path DEFAULT_CLASS_DIR = Paths.get("F://eclipse-jee-2018-12-R-win32-x86_64","ClassLoader");
	 private final Path classDir;
	 //使用默认路径
	 public MyClassLoader() {
		 super();
		 this.classDir=DEFAULT_CLASS_DIR;
	 }
	 //传入指定路径
	 public MyClassLoader(String classDir) {
		 super();
		 this.classDir=Paths.get(classDir);
	 }
	 //传入指定路径,指定父加载器
	 public MyClassLoader(String classDir,ClassLoader parent) {
		 super(parent);
		 this.classDir=Paths.get(classDir);
	 }
	 
	 @Override
	 protected Class<?> findClass(String name) throws ClassNotFoundException {
		byte[] classBytes = this.readClassBytes(name);
		if(classBytes == null || classBytes.length==0) {
			throw new ClassNotFoundException("can not loade the class "+name);
		}
		return this.defineClass(name,classBytes, 0,classBytes.length);
	}
	 //将class文件读入内存
	private byte[] readClassBytes(String name) throws ClassNotFoundException {
		String classPath = name.replace(".", "/");
		Path classFullPath = classDir.resolve(Paths.get(classPath+".class"));
		if(!classFullPath.toFile().exists()) {
			throw new ClassNotFoundException("the class "+name+" not found");
		}
		//try() 创建的对象在使用完后自动关闭  不用写finally关闭
		try(ByteArrayOutputStream baos = new ByteArrayOutputStream()){
			Files.copy(classFullPath, baos);
			return baos.toByteArray();
		}catch (IOException e) {
			throw new ClassNotFoundException("loade the class "+name+" error",e);
		}
	}
	@Override
	public String toString() {
		return "my ClassLoader 加载器";
	}
}

需要加载类代码

	public class MyHello {
	static {
		System.out.println("hello world class is my classLoader initialized");
	}
	public String getString() {
		return " my classLoader success";
	}
	 
}

测试类代码

package com.pys.classloader;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class MyClassLoaderTest {

	public static void main(String[] args) throws ClassNotFoundException,
					InstantiationException,
					IllegalAccessException,
					NoSuchMethodException, 
					SecurityException,
					IllegalArgumentException, 
					InvocationTargetException {
		
		MyClassLoader myclassLoader = new MyClassLoader();
		//指定路径
		//MyClassLoader myclassLoader = new MyClassLoader("F:\\eclipse-jee-2018-12-R-win32-x86_64\\testclass");
		Class<?> aclass= myclassLoader.loadClass("com.pys.classloader.MyHello");
		System.out.println("getClassLoader  "+aclass.getClassLoader());
		Object hellow = aclass.newInstance();
		System.out.println("Object hellow  "+hellow);
		Method we = aclass.getMethod("getString");
		String resut = (String) we.invoke(hellow);
		System.out.println("resut "+ resut);
		
		
	}

}

输出
getClassLoader my ClassLoader 加载器
hello world class is my classLoader initialized
Object hellow com.pys.classloader.MyHello@5c647e05
resut my classLoader success

将编译好的class文件放到F:\eclipse-jee-2018-12-R-win32-x86_64\ClassLoader\com\pys\classloader目录下(根据自己情况定),删除源目录下的class文件和java文件。删除文件是因为加载器的双亲委托机制,当前加载器会调用父加载器尝试加载知道最顶层的加载器,所以不删除文件会被系统加载器所加载。

若不想删除class和java文件可以尝试下面的两种方式:

  1. 绕过系统类加载器,直接将扩展类加载器作为MyClassLoader的父加载器。
  2. 指定父类加载器为null.
    因为在扩展类加载器和根加载器中都找不到MyHello类,所以最后会由当前类加载器进行加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值