首页 > 编程知识 正文

什么时候需要自定义类加载器,java自定义异常的步骤

时间:2023-05-03 15:13:27 阅读:11845 作者:1842

前言

java类加载将. class文件加载到内存中,将类的数据结构放在方法区域中,并在堆区域中创建class类的对象(垃圾回收)。 堆栈空间用于存储局部变量和基本数据。 方法结束后清空。

加载类使用类加载器。 加载程序可以是java虚拟机附带的,也可以是用户自定义的。

java附带了虚拟机

根类加载器

由于没有继承ClassLoader,因此调用ClassLoader.getParent ()为空。 扩展类加载器的父类。 加载虚拟机专用的类。

扩展类加载器

加载由java.ext.dirs指定的类,或加载jrelibext目录中的类。 例如Object类。 系统类加载器的父类。

系统类加载器(APP应用程序类加载器)

从classpath或java.class.path中指定的目录加载类。 这是用户定义的类加载器的默认父类加载器。 用户定义的加载器指定父类加载器的方法newclassloader(parent,name )。

父类委托加载

子类加载器在加载过程中,首先尝试加载到父类加载器中。 如果父类加载器失败,则子类加载器将尝试下一次加载。 如果加载失败,将出现ClassNotFound错误。

一个子类加载器只有一个父类加载器。

进入正题

为什么这样的父类会使用委托加载的形式呢?

由于更安全,子类加载器无法加载父类加载器加载的类。 父类加载的类不需要重复加载。 这样可以防止恶意代码冒充java核心库引起风波。

父类加载器与子类加载器之间的关系? (以下简称父类、子类)

父类类似于子类和包装关系,子类命名空间中的所有类都可以加载到父类中,但父类中的类不能加载到子类中。

的加载器如何加载类?

想法:继承ClassLoader,覆盖核心方法findClass,定义专用方法loadClass,将其转换为二进制数据流,然后加载到Class类中。

代码部分

MyClassLoader.java

publicclassmyclassloaderextendsclassloader {

私有字符串路径=' d :\ ";

privatefinalstringfiletype='.class ';

//类加载器名称

私有字符串名称=null;

publicmyclassloader (字符串名称) {

super (;

this.name=name;

}

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

super(parent );

this.name=name;

}

getClassLoader ) )时返回此方法,如果未重载,则显示MyClassLoader的引用地址

公共字符串字符串

return this.name;

}

//设置文件加载路径

公共语音路径(字符串路径) {

this.path=path;

}

protectedclassfindclass (字符串名称) throws ClassNotFoundException{

byte[]data=loadclassdata(name;

//参数off表示什么?

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

}

//.class文件读取到内存中,并以字节数返回

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

文件输入流fis=null;

字节输出流baos=null;

byte [ ]数据=null;

try{

//读取文件内容

name=name.replaceall(((. )、(() );

System.out.println;

//将文件读入数据流

fis=new文件输入(pathname filetype;

baos=new ByteArrayOutputStream (;

int ch=0;

wile((ch=fis.read ) )!=-1 ()

>baos.write(ch);

}

data = baos.toByteArray();

}catch (Exception e){

throw new ClassNotFoundException("Class is not found:"+name,e);

}finally {

// 关闭数据流

try {

fis.close();

baos.close();

}catch (Exception e){

e.printStackTrace();

}

}

return data;

}

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

MyClassLoader loader1 = new MyClassLoader("loader1");

// 获取MyClassLoader加载器

System.out.println("MyClassLoader 加载器:" + MyClassLoader.class.getClassLoader());

// 设置加载类查找文件路径

loader1.setPath("D:\workspace\bac5\java\");

loader(loader1);

}

private static void loader(MyClassLoader loader) throws Exception {

// MyClassLoader 由系统加载器加载,跟test是不同的加载器,会出现NOClassDefFoundError

// 如果类中有package,则加载类名时,需要写全,不然找不到该类,会出现NOClassDefFoundError

Class test = loader.loadClass("test");

Object test1 = test.newInstance();

// test test2 = (test) test1;

// 如果MyClassLoader与test非同一个加载器,访问时,需要用到反射机制

Field v1 = test.getField("v1");// java反射机制,取test中的静态变量

System.out.println("被加载出来的类是:"+v1.getInt(test1));

// 卸载,将引用置空

test = null;

test1 = null;

// 重新加载

test = loader.loadClass("test");

test1 = test.newInstance();

System.out.println("test1 hashcode:"+test1.hashCode());

}

}

test.java

public class test {

public static int v1= 1;

public test(){

System.out.println("调用到了test");

System.out.println("test加载器为:"+this.getClass().getClassLoader());

}

}

注意:

1.package,如果加载的类有package文件,则查找时,class的名字应该为包名.类名,不然会报NOClassDefFoundError。

2.如果两类不是同一个加载器加载,强制转换,会报NOClassDefFoundError错误。

3.不是同一加载器加载的两类如果想访问对方,则需要使用反射机制。

心得

在编写代码的过程中,同一个包下的文件,总是会报NOClassDefFoundError。直至看到含包名文件的存储方式,才发现需要将loadClass的文件名称替换成包名.类名的形式,才能正确加载到类。

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