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

2025-05-29 0 80

本文研究的主要是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都加载好。

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150
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 void 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文件实例解析

总结

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

原文链接:http://blog.csdn.net/chy555chy/article/details/52777749

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Java 动态加载jar和class文件实例解析 https://www.kuaiidc.com/112605.html

相关文章

发表评论
暂无评论