首页 > 编程知识 正文

java类加载器说法正确的是,java三个类加载器

时间:2023-05-04 12:41:43 阅读:17483 作者:3022

在Java虚拟机中加载类包括三个步骤。 链接,初始化。 其中,加载是查找字节流(即由Java编译器生成的类文件)并据此创建类的过程,需要在中途使用类加载器查找字节流。

Java虚拟机的默认类加载器

Java虚拟机提供了三种类型的加载器。 引导类加载器、扩展类加载器和APP应用程序类加载器。 除了引导类加载器之外,所有类加载器都是java.lang.ClassLoader的子类。/lib路径下的核心类库或-Xbootclasspath参数指定的路径下的jar包都位于内存中扩展类加载器是sun.misc.launcher $ ext class loader类,用Java语言实现,是launcher的静态内部类。 /lib/ext目录或系统变量-加载由-Djava.ext.dir指定的位路径中的类库。 父类加载器是null.APP应用程序类加载器,用于加载APP应用程序路径下的类。 此处的路径

请注意,其中的父子类加载器不是继承关系,而是ClassLoader类的parent属性。 让我们看看在Launcher类中创建扩展类加载器的代码。

publicextclassloader (文件[ ] var1) throws IOException { )。

super(getextUrls(var1),ClassLoader ) null,Launcher.factory );

SharedSecrets.getJavaNetAccess ().geturl class path (this ) ).initlookupcache (this );

}

此处父加载器设置为null。

父母委托机制

加载类时,Java虚拟机默认采用父母委托机制。 也就是说,当一个类加载器接收到加载请求时,请求将转发到父类加载器,如果父类加载器在路径下找不到该类,则将其加载到子类加载器中。 让我们看看ClassLoader的laodClass方法。

protectedclassloadclass (字符串名称,布尔资源) )。

throws类ssnotfoundexception

{

已同步(获取分类加载锁定(name ) )。

//首先判断是否加载了类,加载后直接返回

classc=findloadedclass(name;

if(c==null ) {

long t0=System.nanoTime (;

try {

if(Parent!=空) {

//有父类加载器,调用父加载器的loadClass

c=parent.loadclass(name,false );

} else {

调用bootstrap类加载器

c=findbootstrapclassornull (name;

}

}catch(classnotfoundexceptione ) )

//classnotfoundexceptionthrownifclassnotfound

//from the non-nullparentclassloader

}

if(c==null ) {

long t1=System.nanoTime (;

//查找自己指定的类的加载路径下是否有class字节码

c=查找类(name );

//this is the defining class loader; 记录状态

sun.misc.perfcounter.getparentdelegationtime ().addtime ) T1-T0 );

sun.misc.perfcounter.getfindclasstime ().addelapsedtimefrom ) ) T1;

sun.misc.perfcounter.getfindclasses ().increment );

}

}

解析(if )

解决类(c;

}

返回c;

}

}

在此级别,可以避免类的重复加载。 如果父亲已经加载了类,则不需要再次加载子类加载器。 接下来,我们还考虑了安全因素,例如自己编写java.lang.String类并将其委托给父母

机制传递到启动类加载器,而启动类加载器在核心Java API发现这个名字的类,发现该类已被加载,并不会重新加载我们新写的java.lang.String,而直接返回已加载过的String.class,这样保证生成的对象是同一种类型.

自定义类加载器

除了jvm自身提供的类加载器,我们还可以自定义类加载器,我们先写一个Person类

public class Person {

private int age;

private String name;

//省略getter/setter方法

}

我们先看他是由哪个类加载器加载的.

public class TestJava {

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

Person person = new Person();

System.out.println("person是由" + person.getClass().getClassLoader() + "加载的");

}

}

运行结果如下:

我们把Person.class放置在其他目录下

再运行会发生什么,在上面的loadClass方法中其实已经有了答案,会抛出ClassNotFoundException,因为在指定路径下查找不到字节码.

我们现在写一个自定义的类加载器,让他能够去加载person类,很简单,我们只需要继承ClassLoader并重写findClass方法,这里面写查找字节码的逻辑.

public class PersonCustomClassLoader extends ClassLoader {

private String classPath;

public PersonCustomClassLoader(String classPath) {

this.classPath = classPath;

}

private byte[] loadByte(String name) throws Exception {

name = name.replaceAll("\.", "/");

FileInputStream fis = new FileInputStream(classPath + "/" + name

+ ".class");

int len = fis.available();

byte[] data = new byte[len];

fis.read(data);

fis.close();

return data;

}

protected Class> findClass(String name) throws ClassNotFoundException {

try {

byte[] data = loadByte(name);

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

} catch (Exception e) {

e.printStackTrace();

throw new ClassNotFoundException();

}

}

}

我们来测试一下:

public class TestJava {

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

PersonCustomClassLoader classLoader = new PersonCustomClassLoader("/home/shenxinjian");

Class> pClass = classLoader.loadClass("me.shenxinjian.algorithm.Person");

System.out.println("person是由" + pClass.getClassLoader() + "类加载器加载的");

}

}

测试结果如下:

编写自定义类加载器的意义

当class文件不在classPath路径下,如上面那种情况,默认系统类加载器无法找到该class文件,在这种情况下我们需要实现一个自定义的classLoader来加载特定路径下的class文件来生成class对象。

当一个class文件是通过网络传输并且可能会进行相应的加密操作时,需要先对class文件进行相应的解密后再加载到JVM内存中,这种情况下也需要编写自定义的ClassLoader并实现相应的逻辑

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