Java类加载机制

1、java.lang.ClassLoader

功能:用于加载类,根据类名加载类字节码(.class文件),定义一个Class类实例;

常用方法:

01、getParent():获取当前加载器的父类加载器;

02、loadClass(String name):通过指定的类名,加载类字节码,生成一个java.lang.Class的实例;

03、findClass(String name):通过指定的类名,查找对应的Class实例;

04、defineClass(String name, byte[] b, int off, int len):将字节数组转换为Java类,返回Class的实例,这个方式是final的,不可被继承;

2、Java类加载器的类型

01、引导类加载器(Bootstrap Class Loader)

最高层的类加载器,主要用来加载核心类库:jre/lib/rt.jar,它是原生c++编写的,没有继承自java.lang.ClassLoader,在java中无法获取其对象;

02、扩展类加载器(Extensions Class Loader)

中间层的类加载器,它是加载java的扩展库:jre/ext/*.jar,java虚拟机提供了一个扩展库目录,该类加载器会加载该目录的java类;

03、应用类加载器(App Class Loader)

最底层的类加载器,它负责加载CLASSPATH下的类,我们编写的应用程序,都是由该加载器加载的,可以通过this.getClass().getClassLoader()查看名字,类似这样:sun.misc.Launcher$AppClassLoader@15db9742

三种加载器举例 :

public class SnailTest {

	@Test
	public void testClassLoader() {
		// 应用——类加载器
		System.out.println(ClassLoader.getSystemClassLoader());
		// 扩展——类加载器
		System.out.println(ClassLoader.getSystemClassLoader().getParent());
		// 引导——类加载器
		System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
	}
}

输出:

sun.misc.Launcher$AppClassLoader@5cad8086
sun.misc.Launcher$ExtClassLoader@49476842
null

可以看出ClassLoader类是由AppClassLoader加载,它的父亲是ExtClassLoader,ExtClassLoader的父亲无法获取是因为它是用C++实现。

3、自定义类加载器

除了系统提供的三种加载器外,我们还可以自己定义类加载器,实现方法是:

01、编写自定义类,继承java.lang.ClassLoader

02、自己实现一个加载类字节码的方法,比如:将.class文件读取到字节数组,然后再通过父类的defineClass方法构造一个Class实例;

自定义实现:

public class CustomClassLoader extends ClassLoader {

	private String rootPath;

	public CustomClassLoader(String rootPath) {
		this.rootPath = rootPath;
	}

	private byte[] getFileByte(String name) throws IOException {
		File file = new File(rootPath + name + ".class");
		return FileUtils.readFileToByteArray(file);
	}

	protected Class<?> getClass(String name) throws Exception {
		byte[] bytes = getFileByte(name);
		return super.defineClass(name, bytes, 0, bytes.length);
	}

	public static void main(String[] args) {
		CustomClassLoader ccl = new CustomClassLoader("C:\\jvm\\");
		try {
			Class clazz = ccl.getClass("Test");
			Object obj=clazz.newInstance();//这个对象的构造方法会输出construct
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

4、双亲委派机制

某个特定的类加载器在接到加载类的请求时,首先将加载任务委托交给父类加载器,父类加载器又将加载任务向上委托,直到最父类加载器,如果最父类加载器可以完成类加载任务,就成功返回,如果不行就向下传递委托任务,由其子类加载器进行加载。

双亲委派机制的好处:

01、保证java核心库的安全性(例如:如果用户自己写了一个java.lang.String类就会因为双亲委派机制不能被加载,不会破坏原生的String类的加载)

02、避免类重复加载

代理机制:与双亲委派机制相反,代理机制是先自己尝试加载,如果无法加载则向上传递。tomcat就是代理模式。

5、类加载过程

01、装载:读取字节码文件.class文件;

02、链接:

验证:确保加载的.class文件合法,符合jvm规范,没有安全问题;

准备:为类的静态变量分配内存;

解析:把虚拟机常量池中的符号引用转换为直接引用;

03、初始化:为类的静态变量赋予正确的初始值。

说明:解析,Java 中,虚拟机会为每个加载的类维护一个常量池【不同于字符串常量池,这个常量池只是该类的字面值(例如类名、方法名)和符号引用的有序集合。 而字符串常量池,是整个JVM共享的】这些符号(如int a = 5;中的a)就是符号引用,而解析过程就是把它转换成指向堆中的对象地址的相对地址。

6、类的初始化步骤:

01、如果这个类还没有被加载和链接,那先进行加载和链接

02、假如这个类存在直接父类,并且这个类还没有被初始化(注意:在一个类加载器中,类只能初始化一次),那就初始化直接的父类(不适用于接口)

03、如果类中存在static标识的块,那就依次执行这些初始化语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值