Java 动态加载jar和class文件实例解析

网友投稿 409 2023-02-20


Java 动态加载jar和class文件实例解析

本文研究的主要是java 动态加载jar和class文件的相关内容,具体如下。

JAVA中类文件加载是动态的。也就是说当我们用到的时候才会去加载,如果不用的话,就不会去加载我们的类。

JAVA为我们提供了两种动态机制。第一种是隐式机制。第二种是显示机制。如下:

两种方法:

隐式机制 :new一个对象 + 调用类的静态方法

显式机制 :由 java.lang.Class的forName()方法加载

由 java.lang.ClassLoader的loadClass()方法加载

1、Class.forName

Class.forName()方法具有两个形式:

public static Class forName(String className)

public static Class forName(String className, boolean initialize,ClassLoader loader)

参数说明:

className - 所需类的完全限定名 (必须包含包名,否则出错!)

initialize - 是否必须初始化类 (静态代码块的初始化)

loader - 用于加载类的类加载器

调用只有一个参数的forName()方法等效于 Class.forName(className, true, loader)。

这两个方法,最后都要连接到原生方法forName0().

而三个参数的forName(),最后调用的是: forName0(name, initialize, loader);

不管使用的是new 來实例化某个类、或是使用只有一个参数的Class.forName()方法,内部都隐含了“载入类 + 运行静态代码块”的步骤。

而使用具有三个参数的Class.forName()方法时,如果第二个参数为false,那么类加载器只会加载类,而不会初始化静态代码块,只有当实例化这个类的时候,静态代码块才会被初始化,静态代码块是在类第一次实例化的时候才初始化的。

2、java.lang.ClassLoader

ClassLoader就是用来Load Class的,当一个Class被加载的时候,这个Class所引用到的所有Class也会被加载,而且这种加载是递归的,也就是说,如果A引用到B,B 引用到C,那么当A被加载的时候,B也会被加载,而B被加载的时候,C也会加载。如此递归直到所有需要的Class都加载好。

package com.demo.test;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.lang.reflect.Field;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.net.MalformedURLException;

import java.net.URL;

import java.net.URLClassLoader;

public class DynamicLoadDemo {

enum FileType {

JAR, CLASS, OTHER

}

static class MyClassLoader extends ClassLoader {

public synchronized Class> loadClass(String name, File file) throws FileNotFoundException {

Class> cls = findLoadedClass(name);

if(cls != null) {

return cls;

}

FileInputStream fis = new FileInputStream(file);

ByteArrayOutputStream baos = new ByteArrayOutputStream();

byte[] buffer = new byte[1024];

int len;

try {

while (true) {

len = fis.read(buffer);

if (len == -1) {

break;

}

baos.write(buffer, 0, len);

}

//FileInputStream的flush是空操作,因为flush的作用是把缓存中的东西写入实体(硬盘或网络流)中,这里没有这种必要所以为空

//baos.flush();

byte[] data = baos.toByteArray();

return defineClass(null, data, 0, data.length);

}

catch (IOException e) {

e.printStackTrace();

}

finally {

try {

baos.close();

}

catch (IOException e) {

e.printStackTrace();

}

try {

fis.close();

}

catch (IOException e) {

e.printStackTrace();

}

}

return null;

}

}

public static vhttp://oid main(String[] args) {

String className = "com.demo.test.HelloWorld";

String paths[] = { "HelloWorld.jar", "HelloWorld.class" };

for (String path : paths) {

String lowerPath = path.toLowerCase();

FileType fileType = FileType.OTHER;

if (lowerPath.endsWith(".jar") || lowerPath.endsWith(".zip")) {

fileType = FileType.JAR;

} else if (lowerPath.endsWith(".class")) {

fileType = FileType.CLASS;

}

if (fileType == FileType.OTHER) {

return;

}

File file = new File(path);

if (!file.exists()) {

return;

}

try {

URL url = file.toURI().toURL();

System.out.println(url.toString());

Class> cls = null;

switch (fileType) {

case JAR:

URLClassLoader classLoader = new URLClassLoader(new URL[] { url }, Thread.currentThread().getContextClassLoader());

cls = classLoader.loadClass(className);

break;

case CLASS:

MyClassLoader myClassLoader = new MyClassLoader();

cls = myClassLoader.loadClass(className, file);

break;

default:

break;

}

if (cls == null) {

return;

}

// 实例变量

Field field = cls.getDeclaredField("hello");

if (!field.isAccessible()) {

field.setAccessible(true);

}

System.out.println(field.get(cls.newInstance()));

// 调用静态不带参数方法

Method staticMethod = cls.getDeclaredMethod("sayStaticHello", null);

if (!staticMethod.isAccessible()) {

staticMethod.setAccessible(true);

}

// 如果函数的返回值是void,就会返回null

staticMethod.invoke(cls, null);

// 实例带参数方法方法

Method method = cls.getDeclaredMethod("say", String.class);

if (!method.isAccessible()) {

method.setAccessible(true);

}

Object ret = method.invoke(cls.newInstance(), "hello world");

System.out.println(ret);

}

catch (MalformedURLException e) {

e.printStackTrace();

}

catch (ClassNotFoundException e) {

e.printStackTrace();

}

catch (NoSuchMethodException e) {

e.printStackTrace();

}

catch (SecurityException e) {

e.printStackTrace();

}

catch (IllegalAccessException e) {

e.printStackTrace();

}

catch (IllegalArgumentException e) {

e.printStackTrace();

}

catch (InvocationTargetException e) {

e.printStackTrace();

}

catch (InstantiationException e) {

e.printStackTrace();

}

catch (NoSuchFieldException e) {

e.printStackTrace();

}

catch (FileNotFoundException e) {

e.printStackTrace();

}

}

}

}

结果:

总结

以上就是本文关于Java 动态加载jar和class文件实例解析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详细介绍高性能Java缓存库Caffeine
下一篇:Spring启动后获取所有拥有特定注解的Bean实例代码
相关文章

 发表评论

暂时没有评论,来抢沙发吧~