ClassLoader类加载机制

前言

Java程序是由class文件组成的一个完整的应用程序。在程序运行时,并不会一次性加载所有的class文件进入内存,而是通过Java的类加载机制进行动态加载,从而转换成java.lang.Class类的一个实例。

ClassLoader类

ClassLoader是一个抽象类,主要功能是通过指定的类的名称,找到或生成对应的字节码,返回一个java.lang.Class类的实例。开发者可以继承ClassLoader类来实现自定义的类加载器。

方法说明
getParent()返回该类加载器的父类加载器
loadClass(String name)加载名称为name的类,返回的结果是java.lang.Class类的实例
findClass(String name)查找名称为name的类,返回的结果是java.lang.Class类的实例
findLoadedClass(String name)查找名称为name的已经被加载过的类,返回的结果是java.lang.Class类的实例
defineClass(String name,byte[] b,int off,int len)把字节数组b中的内容转换成Java类,返回的结果是java.lang.Class类的实例,该方法被声明为final
resolveClass(Class<?> c)链接指定的Java类

loadClass()方法的流程

当loadClass()方法被调用时,会首先使用findLoadedClass()方法判断该类是否已经被加载,如果未被加载,则优先使用加载器的父类加载器进行加载。当不存在父类加载器,无法对该类进行加载时,则会调用自身的findClass()方法,因此可以重写findClass()方法来完成一些类加载的特殊要求。

protected Class<?> loadClass(String name,boolean resolve) throws ClassNotFoundException
{
	synchronized(getClassLoadingLock(name)){
		Class<?> c = findLoadedClass(name);
		if(c == null){
			long t0 = System.nanoTime();
			try{
				if(parent != null){
					c = parent.loadClass(name,false);
				}else{
					c = findBootstrapClassOrNull(name);
				}
			}catch(ClassNotFoundException e){
				//省略
			}
			if (c == null){
				//省略
				c = findClass(name);
				//省略
			}
		}
		if (resolve){
			resolveClass(c);
		}
		return c;
	}
}

自定义的类加载器

根据loadClass()方法的流程,可以发现通过重写findClass()方法,利用defineClass()方法来将字节码转换成java.lang.Class类对象,就可以实现自定义的类加载器。

hello.class

package com.atguigu.java;

public class hello {

    public void sayHello(){
        System.out.println("hello~");
    }
}

DemoClassLoader.class

package com.atguigu.java;

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

public class DemoClassLoader extends ClassLoader{

    private byte[] bytes;
    private String name = "";

    public DemoClassLoader(String name, byte[] bytes) {
        this.name = name;
        this.bytes = bytes;
    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException{
        if(name.equals(this.name)){
            defineClass(name,bytes,0,bytes.length);
        }
        return super.findClass(name);
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        String clzzName = "com.atguigu.java.hello";
        byte[] testBytes = new byte[]{
            -54,-2,-70,-66,0,0,0,52,0,28,10,0,6,0,14,9,
                0,15,0,16,8,0,17,10,0,18,0,19,7,
                0,20,7,0,21,1,0,6,60,105,110,105,116,62,1,0,
                3,40,
        };
        DemoClassLoader demo = new DemoClassLoader(clzzName,testBytes);
        Class clazz = demo.loadClass(clzzName);
        Constructor constructor = clazz.getConstructor();
        Object obj = constructor.newInstance();
        Method method = clazz.getMethod("sayHello");
        method.invoke(obj);
    }
}

在这里插入图片描述

loadClass()方法与Class.forName的区别

loadClass()方法只对类进行加载,不会对类进行初始化。Class.forName会默认对类进行初始化。当对类进行初始化时,静态的代码块就会得到执行,而代码块和构造函数则需要适合的类实例化才能得到执行

Dog.class

package com.atguigu.java;

public class Dog {

    static {
        System.out.println("静态代码块执行");
    }
    {
        System.out.println("代码块执行");
    }

    public Dog() {
        System.out.println("构造方法执行");
    }
}

ClassLoaderTest.class

package com.atguigu.java;

public class ClassLoaderTest {
    public static void main(String[] args) throws ClassNotFoundException{
        Class.forName("com.atguigu.java.Dog");
        ClassLoader.getSystemClassLoader().loadClass("com.atguigu.java.Dog");
    }
}

在这里插入图片描述

URLClassLoader

URLClassLoader类是ClassLoader的一个实现,拥有从远程服务器上加载类的能力。通过URLClassLoader可以实现对一些WebShell的远程加载、对某个漏洞的深入利用。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

平凡的学者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值