首页 > 编程知识 正文

java自定义标签实现类,Java自定义类加载器

时间:2023-05-06 19:12:46 阅读:32276 作者:4163

java类加载器主要分为以下几类:

jvm提供的类加载器

根加载器:一种基本实现,主要加载java核心类库。 示例: java.lang.* )

扩展类库:使用java代码实现,主要加载扩展类库,如jre/lib/ext/。 (父类加载器是根类加载器)

系统类加载器(APP应用程序类加载器)使用java代码实现加载classpath目录下的类。 (父类加载器是扩展类加载器)

用户定义的类加载器:继承ClassLoader类以实现自定义类加载器。

类加载器负责将java字节码文件加载到虚拟机内存(即类的生命周期)中的过程。 (类的生命周期如下所示)

类的生命周期图

下面是实现用户定义类加载器的步骤和代码。

要实现用户定义的类加载器,必须继承ClassLoader类并重写findClass方法,如下所示

package com.space;

import Java.io.bytearray output stream;

import java.io.File;

import java.io.FileInputStream;

import Java.io.file not found exception;

import java.io.IOException;

import java.io.InputStream;

publicclassmyclassloaderextendsclassloader {

私有路径='/home/luciel/'; //默认加载路径

私有字符串名称; //类加载器名称

privatefinalstringfiletype='.class '; //文件类型

publicmyclassloader (字符串名称) {

//todo自动生成构造函数

super (;

this.name=name;

}

publicmyclassloader (类加载器parent,字符串名称)。

super(parent );

this.name=name;

}

@Override

publicclassfindclass (字符串名称) throws ClassNotFoundException {

//todo自动- generated method stub

byte[]b=loadclassdata(name );

returndefineclass(name,b,0,b.length );

}

private byte [ ] loadclassdata (字符串名称) {

byte [ ]数据=null;

InputStream in=null;

name=name.replace ('.','/' );

bytearrayoutputstreamout=newbytearrayoutputstream (;

try {

in=new文件输入(new file (pathname filetype ) );

int len=0;

wile(-1!=(len=in.read ) () ) ) ) 0

out.write(len;

}

data=out.toByteArray (;

}catch(filenotfoundexceptione ) {

//todo auto-generated catch块

e .打印堆栈跟踪(;

}catch(ioexceptione ) {

//todo auto-generated catch块

e .打印堆栈跟踪(;

}finally{

try {

in.close (;

out.close (;

}catch(ioexceptione ) {

//todo auto-generated catch块

e .打印堆栈跟踪(;

}

}

返回数据;

}

公共字符串获取路径

返回路径;

}

公共语音设置路径(stri

ng path) {

this.path = path;

}

@Override

public String toString() {

// TODO Auto-generated method stub

return this.name;

}

}

public MyClassLoader(String name) {

// TODO Auto-generated constructor stub

super();

this.name=name;

}

这个构造方法中去调用ClassLoader无参构造方法从ClassLoader源码中可以得出:调用此构造方法会让系统类加载器成为该类加载器的父加载器。(注意:此处父类加载器不一定是继承关系,只是一种包装关系)。

在重写findClass方法时参照java API中实现一个网络类加载器的例子,API例子如下:

class NetworkClassLoader extends ClassLoader {

String host;

int port;

public Class findClass(String name) {

byte[] b = loadClassData(name);

return defineClass(name, b, 0, b.length);

}

private byte[] loadClassData(String name) {

// load the class data from the connection

. . .

}

}

下面是测试类以及main方法类的测试代码:

1 package com.space;

2

3 public class Color {

4 public Color() {

5 // TODO Auto-generated constructor stub

6 System.out.println("Color is loaded by "+this.getClass().getClassLoader());

7

8 }

9 }

1 package com.space;

2

3 public class Red extends Color{

4

5 public Red() {

6 // TODO Auto-generated constructor stub

7 System.out.println("Red is loaded by "+this.getClass().getClassLoader());

8

9 }

10

11 }

1 package com.space;

2

3 public class TestMyClassLoader {

4

5 public static void main(String[] args) throws Exception {

6

7 MyClassLoader loader1=new MyClassLoader("loader1");

8

9 loader1.setPath("/home/luciel/test1/");

10

11 MyClassLoader loader2=new MyClassLoader(loader1, "loader2");

12

13 loader2.setPath("/home/luciel/test2/");

14

15 MyClassLoader loader3=new MyClassLoader(null, "loader3");

16

17 loader3.setPath("/home/luciel/test3/");

18

19 loadClassByMyClassLoader("com.space.Red",loader2);

20

21 loadClassByMyClassLoader("com.space.Red",loader3);

22 }

23

24 private static void loadClassByMyClassLoader(String name,ClassLoader loader) throws Exception{

25

26 Class> c=loader.loadClass(name);

27 Object obj=c.newInstance();

28 }

29

30 }

按照main方法中给三个类加载器传入的路径创建相应的环境并将com.space.Red、com.space.Color的class类拷贝到

/home/luciel/test1/和/home/luciel/test2/以及/home/luciel/test3/目录中去将com.space.TestMyClassLoader类和com.space.MyClassLoader拷贝

/home/luciel/main/ 中去并在该目录下执行

最终运行结果如下显示:

[root@localhost main]# java com.space.TestMyClassLoader

Color is loaded by loader1

Red is loaded by loader1

Color is loaded by loader3

Red is loaded by loader3

loadClassByMyClassLoader("com.space.Red",loader2);如测试代码中 我们调用了loader2去加载Red类但Red类却打印出由loader1加载,这是由于类加载器秉承的是父委托机制loader2在创建时包装了loader1为其父类加载器,而loader1创建时由于调用的是没有传入父类加载器的构造方法,因此它的父加载器为系统类加载器。因此几个加载器的关系如下:

由于loader1的路径下有Red类class文件所以loader1可以加载,因此载Red类构造方法中打印的类加载器为loader1.

我门看似只去加载了Red类但运行结果却将Color父类加载了,而且Color类的加载在Red类之前,那是由于Red类主动使用 了Color类,因此在初始化Red类之前必须先初始化Color类,要初始化就必须先加载,所以先打印出了Color类的输出信息。(关于类的主动使用大家如果不清楚可以查查,一共有6种)

loadClassByMyClassLoader("com.space.Red",loader3);再分析第二个测试代码,由于loader3创建时传入的父类加载器为 null,看下面关于ClassLoader类源码部分代码或查看java API

/**

* Returns the parent class loader for delegation. Some implementations may

* use null to represent the bootstrap class loader. This method

* will return null in such implementations if this class loader's

* parent is the bootstrap class loader.

*

*

If a security manager is present, and the invoker's class loader is

* not null and is not an ancestor of this class loader, then this

* method invokes the security manager's {@link

* SecurityManager#checkPermission(java.security.Permission)

* checkPermission} method with a {@link

* RuntimePermission#RuntimePermission(String)

* RuntimePermission("getClassLoader")} permission to verify

* access to the parent class loader is permitted. If not, a

* SecurityException will be thrown.

*

* @return The parent ClassLoader

*

* @throws SecurityException

* If a security manager exists and its checkPermission

* method doesn't allow access to this class loader's parent class

* loader.

*

* @since 1.2

*/

@CallerSensitive

public final ClassLoader getParent() {

if (parent == null)

return null;

SecurityManager sm = System.getSecurityManager();

if (sm != null) {

checkClassLoaderPermission(parent, Reflection.getCallerClass());

}

return parent;

}

getParent方法的说明如下部分文字:

Returns the parent class loader for delegation. Some implementations may * use null to represent the bootstrap class loader. This method * will return null in such implementations if this class loader's * parent is the bootstrap class loader.

意思是说我们可以使用null表示 the bootstrap class loader(根类加载器)那么loader3的父类加载器就是** 根类加载器 **,而根类加载器只会去加载那些系统核心类库,显然我们的Red和Color类不属于此范围,而就只能让loader3加载,loader3的加载路径下有这两个类对应的字节码可以成功加载,所以大引出Red和Color类的类加载器为loader3

以上是自己最近在学习jvm时有关类加载器的相关知识总结。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。