java classloader解析_Java--ClassLoader解析

ClassLoader

类从编译到执行的过程

编译器将Robot.java源文件编译为Robot.class字节码文件

ClassLoader将字节码转换成JVM中的Class对象

JVM利用Class对象实例化为Robot对象

定义: ClassLoader在java中有着非常重要的作用,它主要工作在Class装载的加载阶段,主要作用是从系统外部获得Class二进制数据流。它是java的核心组件,所有的class都是由ClassLoader进行加载的,ClassLoader负责通过将Class文件里的二进制数据流装载进系统,然后交给java虚拟机(JVM)进行连接、初始化等操作

种类

BootStrapClassLoader:C++编写,加载核心库java.*

ExtClassLoader:java编写,加载扩展库javax.*

AppClassLoader: java编写,加载程序所在目录(我们自己编写的代码)

自定义ClassLoader: java编写,定制化加载

实现自定义ClassLoader:

注意:使用defineClass生成Class文件,重写findClass制定加载class的路径

首先使用javac生成一个Wali.class

public Class Wali{

static{

System.out.println("hello Wali");

}

}

编写自定义ClassLoader:

public class MyClassLoader extends ClassLoader {

private String path;

private String classLoaderName;

public MyClassLoader(String path, String classLoaderName) {

this.path = path;

this.classLoaderName = classLoaderName;

}

//用于寻找类文件

@Override

public Class findClass(String name) {

byte[] b = loadClassData(name);

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

}

//用于加载类文件

private byte[] loadClassData(String name) {

name = path + name + ".class";

InputStream in = null;

ByteArrayOutputStream out = null;

try {

in = new FileInputStream(new File(name));

out = new ByteArrayOutputStream();

int i = 0;

while ((i = in.read()) != -1) {

out.write(i);

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

out.close();

in.close();

} catch (Exception e) {

e.printStackTrace();

}

}

return out.toByteArray();

}

}

运行:

public class ClassLoaderChecker {

public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

MyClassLoader m = new MyClassLoader("/Users/Desktop/", "myClassLoader");

Class c = m.loadClass("Wali");

System.out.println(c.getClassLoader());

System.out.println(c.getClassLoader().getParent());

System.out.println(c.getClassLoader().getParent().getParent());

System.out.println(c.getClassLoader().getParent().getParent().getParent());

c.newInstance();

}

}

5066a1de888c

自定义ClassLoader

双亲委派机制

5066a1de888c

双亲委派机制

定义:

首先自底向上查找class是否已经被装载了,若已加载直接返回,否则向上继续查找,若找到最顶层BoostrapClassLoader依然没有发现,说明该class没有被装载进内存成为Class对象,则需要自顶向下的尝试装载该class,若能装载成功则直接返回,否则依次向下寻找,直到最底层依然不能装载则抛出异常,

代码:ClassLoader

protected Class> loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

synchronized (getClassLoadingLock(name)) {

// First, check if the class has already been loaded

Class> c = findLoadedClass(name);

1 if (c == null) {

long t0 = System.nanoTime();

try {

2 if (parent != null) {

c = parent.loadClass(name, false);

} else {

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

// ClassNotFoundException thrown if class not found

// from the non-null parent class loader

}

if (c == null) {

// If still not found, then invoke findClass in order

// to find the class.

long t1 = System.nanoTime();

c = findClass(name);

// this is the defining class loader; record the stats

sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);

sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);

sun.misc.PerfCounter.getFindClasses().increment();

}

}

if (resolve) {

resolveClass(c);

}

return c;

}

}

当加载字节码文件时,首先会加上同步锁防止别的类加载器去加载,在标记1处判断当前类加载器是否加载过,标记2处如果父类加载器不为空,调用父类加载器的loadClass方法迭代排查是否加载过。 这就符合了上面定义对双亲委派机制的介绍,从上方图片自定义ClassLoader中也能看到它们是这样的关系

为什么要使用双亲委派机制去加载类

避免同个字节码重复加载,浪费内存

类的加载方式

隐式加载:new

显示加载:loadClass、forName等

类的装载(加载)过程如下图:

5066a1de888c

loadClass和forName的区别

Class.forName得到的class是已经初始化完成了的 (MySQL加载驱动时,需要调用静态代码块完成一些操作)

ClassLoader.loadClass得到的class是还没有链接的。(用于Spring IoC中的延迟加载机制)

代码验证上面结论

用来加载的类:

public class Robot {

static {

System.out.println("Hello Robot");

}

}

使用loadClass加载:

public class LoadDifference {

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

ClassLoader cl = Robot.class.getClassLoader();

}

}

5066a1de888c

loadClass

结论:没有执行静态代码块的代码,符合结论

使用forName:

public class LoadDifference {

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

Class r = Class.forName("com.interview.javabasic.reflect.Robot");

}

}

5066a1de888c

forName

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值