java中class怎么描述_Java中的ClassLoader具体解说

java中的.java文件经过编译今后,号码大全就会生成类文件.class文件关键词挖掘工具。class文件是以二进制字节码寄存在硬盘中的。当咱们需求运用或加载Java文件到JVM中的时分,会从硬盘中读取字节码的class文件,然后经过类加载器将class文件加载到JVM中。也即是说,一切的Java文件都是经过类加载器加载到JVM中的。当然类加载器也是一个Java文件。那么第一个类加载器又是怎么加载到JVM中的呢?在发动JVM的时分,会调运一个本地办法findBootStrapClass办法加载最初始的那个ClassLoader,private native Class findBootstrapClass(String name),这个本地办法运用C++编写的。

1.体系已有3品种加载器

1.1 BooststrapClassLoader(boot) 加载rt.jar下面的类(此加载器采用C++编写,通常开发中是看不到的)

1.2 ExtClassLoader  加载ExtClassLoader下面的类(ext文件夹下面的jar)

1.3 AppClassLoader  加载classpaht下面的类

咱们写的类简直都是经过AppClassLoader这个加载器加载到JVM中的。

2.类加载器的加载机制(双亲托付机制)

每一个类加载器都有一个对应的parentClassLoader。

2.1    体系类加载器的父子关系

自界说类加载器的爸爸是AppClassLoader

AppClassLoader的爸爸是ExtClassLoader

ExtClassLoader的爸爸是BooststrapClassLoader

Java代码  保藏代码

public class TestClassLoader {

public static void main(String[] args) {

// 当时目标的类加载器

ClassLoader loader = new TestClassLoader().getClass().getClassLoader();

// 从当时目标的类加载器想上找他的各个祖先

while (loader != null) {

System.out.println(loader.getClass().getName());

loader = loader.getParent();

}

// 晓得找到最终的祖先是null

System.out.println(loader);

}

}

输出:

sun.misc.Launcher$AppClassLoader

sun.misc.Launcher$ExtClassLoader

null

2.2    类加载器加载的次序

类加载器是从根向下加载的

也即是boot-》ExiClassLoader -》AppClassLoader

当一个类需求被加载的时分,首要是由AppClassLoader加载器将其传递给其爸爸ExtClassLoader,然后ExtClassLoader再将其传递给他的爸爸boot。

当boot发现他的加载规模内有对应的class,就加载到JVM中,否则交给儿子ExtClassLoader处置。

ExtClassLoader再在他的加载规模类找有没有对应的class,有就加载到JVM中,没有就交给AppClassLoader处置。

AppClassLoader再在classpath途径下找对应的class,找到就加载,没有就报反常。

缘由:这样能够确保JVM中某一个className对应的是同一个class,由于都是从根向下加载的。

避免重复加载,当爸爸现已加载了该类的时分,就没有必要子ClassLoader再加载一次。

要是从下向上加载,能够致使某一个className在JVM中对应好几个class。能够咱们会界说自个的类加载器和自个的加载规模。

当自个界说的类加载在他们各自的规模都发现需求加载的类,那么他们能够都会加载,致使JVM中一个className对应好几个不一样的class

2.3    比方咱们自个界说一个类加载器去加载java.lang.String这个类,那么咱们是不能到达咱们目的的。

由于加载机制是从上到下加载,当传递到上面的boot的时分,现已被加载到JVM中,轮不到咱们自界说的类加载器去加载它。

但是,咱们肯定是能够自个界说一个类加载器去加载咱们指定的类的。

3.怎么自界说一个类加载

首要,咱们需求承继ClassLoadar

然后,咱们不能破坏本来的类加载机制(双亲托付机制),所以咱们不能掩盖loadClass办法,咱们需求掩盖findclass办法。

最终,在findClass办法中写入咱们的类加载器的代码。

查看源码解说:

Java代码  保藏代码

protected Class loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

synchronized (getClassLoadingLock(name)) {

// 首要查看name对应的Class是不是现已被加载

Class c = findLoadedClass(name);

//假如没有被加载

if (c == null) {

long t0 = System.nanoTime();

//测验让parentClassLoader去加载

try {

if (parent != null) {

//当parent不为null的时分,让parent去loadClass

c = parent.loadClass(name, false);

} else {

//当parent为null的时分,就调运本地办法

c = findBootstrapClassOrNull(name);

}

} catch (ClassNotFoundException e) {

}

//当parentClassLoader没有加载的时分

if (c == null) {

long t1 = System.nanoTime();

//调运findClass办法去加载

c = findClass(name);

}

}

-        indexRead arguments from command-line "http://www.shoudashou.com"

-        indexRead arguments from command-line "http://www.4lunwen.cn"

-        indexRead arguments from command-line "http://www.zx1234.cn"

-        indexRead arguments from command-line "http://www.penbar.cn"

-        indexRead arguments from command-line "http://www.whathappy.cn"

-        indexRead arguments from command-line "http://www.lunjin.net"

-        indexRead arguments from command-line "http://www.ssstyle.cn"

-        indexRead arguments from command-line "http://www.91fish.cn"

-        indexRead arguments from command-line "http://www.fanselang.com"

if (resolve) {

resolveClass(c);

}

return c;

}

}

4.举例

目标:自界说一个类加载器加咱们指定途径下,经过我么加密的class。

进程:找到指定途径下的class文件,解密,加载到JVM中。

4.1先界说一个需求被加密编译的类,一起运用它进行测验

Java代码  保藏代码

public class MyClass extends Date {

@Override

public String toString() {

return "hello world";

}

}

4.2加密本来的class文件

Java代码  保藏代码

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

String inputSrc = args[0];//本来的class文件的途径和文件名

String outputSrc = args[1];//加密今后寄存的文件途径和文件名

FileInputStream fis = new FileInputStream(inputSrc);

FileOutputStream fos = new FileOutputStream(outputSrc);

//调用加密算法

cypher(fis, fos);

fis.close();

fos.close();

}

/**

* 加密解密函数办法

*

* @param is

* @param os

* @throws IOException

*/

private static void cypher(InputStream is, OutputStream os) throws IOException {

int b = -1;

while ((b = is.read()) != -1) {

// 将0成为1,将1成为0

os.write(b ^ 0xff);

}

}

4.3编写咱们自个的类加载器

Java代码  保藏代码

public class MyClassLoader extends ClassLoader {

//要加载的类的途径

private String clas***c;

public MyClassLoader() {

}

public MyClassLoader(String clas***c) {

this.clas***c = clas***c;

}

@Override

protected Class findClass(String name) throws ClassNotFoundException {

//先找到自个的加密的class文件的方位

String classFielName = clas***c + "\\" + name + ".class";

try {

FileInputStream fis = new FileInputStream(classFielName);

ByteArrayOutputStream baos = new ByteArrayOutputStream();

//调运解密算法

cypher(fis, baos);

fis.close();

byte[] bytes = baos.toByteArray();

//将读出来的二进制转换为Class字节码

return defineClass(null, bytes, 0, bytes.length);

} catch (Exception e) {

e.printStackTrace();

}

return super.findClass(name);

}

}

4.4运用咱们自个的类加载加载咱们加密的类到JVM中

Java代码  保藏代码

//首要运用自个的类加载器去加载咱们加密的class文件

//留意,这个当地的加载类的途径下的class应该是咱们加密今后文件的方位

Class clazz = new MyClassLoader("E:/AllWorkspace/workspace1/classLoaderTest/bin/com/gusi/test").loadClass("MyClass");

//经过反射,测验咱们的classLoader

Date date = (Date) clazz.newInstance();

System.out.println(date.toString());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值