Java动态连接

  • Post author:
  • Post category:java


当编译一个Java程序的时候,会得到程序中每个类或者接口的独立的class文件,当程序运行的时候,JVM转载程序的类和接口,在动态连接的过程中把它们互相勾连起来。

Class文件把它所有的符号引用保存在常量池。

  • 常量池:每一个被JVM装载的类或接口都有一份内部版本的常量池
  • 运行时常量池:常量池中的符号引用被解析后放入运行时常量池


因此,当一个类型被首次装载时,所有来自该类型的符号引用都装载到了类型的运行时常量池。


而经过解析(resolve)之后,也就是把符号引用替换为直接引用,解析的过程会去查询全局字符串池,也就是StringTable,以保证运行时常量池所引用的字符串与全局字符串池中所引用的是一致的。



一.解析和动态扩展

除了简单地在运行时连接类型之外,Java还可以在运行时决定连接哪一个类型:

  • 通过传递类型的名字到java.lang.Class.forName()
  • 或者用户自定义的类装载器的loadClass()方法


1.forName()

:

在这里插入图片描述

其中,initialize – 是否必须初始化类,如果为true,类型会在方法返回之前连接并初始化,为false的话,类型会被装载但可能不会被明确地初始化。

而如果类型无法被装载则会抛出classnotfount

它的作用:

这里是引用

在这里插入图片描述


2.loadClass()

:

在这里插入图片描述

但这是protected权限的,在我们自己写的程序中不能直接吊带resolve参数的,一下方法默认resolve==false:

在这里插入图片描述

在这里插入图片描述

两者区别及用法:

在这里插入图片描述

在这里插入图片描述



总结:

1.动态加载一个类到jvm有两种方式:loadclass()和forname()

2.类加载包括加载,加载和初始化是两码事

3.JDBC使用的forname(),因为要其中有静态代码块,要初始化;spring ioc中的bean使用的是类加载器

4…类加载器的loadclass()是线程安全的



二.类装载器与双亲委派模型

https://blog.csdn.net/qq_39327985/article/details/83032918


自定义类加载器:

  1. 自定义类加载器
/**
 *自定义类加载器
*/
class MyClassLoader extends ClassLoader {
    private String path;

    public MyClassLoader(String path) {
        this.path = path;
    }
    // 重写findClass方法
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        System.out.println("findClass method has been implemented");
        Class log = null;
        // 获取该class文件字节码数组
        byte[] classData = getData();

        if (classData != null) {
            // 将class的字节码数组转换成Class类的实例
            log = defineClass(name, classData, 0, classData.length);
        }

        return log;
    }
/**
     * 将class文件转化为字节码数组
     * @return
     */
    private byte[] getData() {

        File file = new File(path);
        if (file.exists()) {
            FileInputStream in = null;
            ByteArrayOutputStream out = null;
            try {
                in = new FileInputStream(file);
                out = new ByteArrayOutputStream();

                byte[] buffer = new byte[1024];
                int size = 0;
                while ((size = in.read(buffer)) != -1) {
                    out.write(buffer, 0, size);
                }

            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    in.close();
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
            return out.toByteArray();
        } else {
            return null;
        }
    }
}
  1. main方法中配置参数
/**
 1. @author nsu_zk
 2. @create 2019-07-30 19:46
 */
public class Test9 {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
        String path = "D:\\workspace\\CodeTest\\bin\\CodeTest\\tet.class";
        MyClassLoader myClassLoader = new MyClassLoader(path);
        try {
            Class<?> aClass = myClassLoader.loadClass("CodeTest.tet");
            System.out.println(aClass);
            Method method = aClass.getDeclaredMethod("main", String[].class);
            Object object = aClass.newInstance();// 这会执行静态代码块中的语句
            String[] arg = {};
            method.invoke(object, (Object) arg);

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  1. 被加载的类
package CodeTest;

public class tet {
	static {
		System.out.println("Static code blocks are executed");
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println("Main method has been implemented");
	}

}
  1. result

    在这里插入图片描述



版权声明:本文为qq_39327985原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。