黑马程序员-----类加载器

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------


一、类加载器简介

1、加载类的工具就是类加载器,在java程序中用到一个类,那么首先java虚拟机要把类的字节码加载到内存中(通常字节码放在硬盘中的classPath路径指定的目录下),然后再进行一些工作bian


2、java虚拟机中提供了多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap、ExtClassLoader、AppClassLoader;

注意:类加载器也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载不是java类,这个就是BootStrap;


3、java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其制定一个父级类加载器对象或者默认系统类加载器为其父级类加载;

类加载器之间的父子关系和管辖范围

BootStrap<--子类--ExtClassLoader<--子类--AppClassLoader

B:JRE/lib/rt.jar

E:JRE/lib/ext/*.jar

A:CLASSPATH指定的所有jar或目录


二、编写自己的类加载器

1、必须继承ClassLoader类

2、重写findClass方法(知道loadClass类方法与findClass方法、defineClass方法)

3、自己编写加密类加载器

import java.util.Date;
public class ClassLoaderAttachment extends Date {
public String toString(){
return "hello itcast";
}
}


import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
public class MyClassLoader extends ClassLoader{
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
String srcPath = args[0];
String destDir = args[1];
FileInputStream fis = new FileInputStream(srcPath);
String destFileName = srcPath.substring(srcPath.lastIndexOf('\\')+1);
String destPath = destDir+"\\"+destFileName;
FileOutputStream fos = new FileOutputStream(destPath);
cypher(fis,fos);
fis.close();
fos.close();
}
private static void cypher(InputStream ips,OutputStream ops)throws Exception{
int b = -1;
while((b = ips.read()) != -1){
ops.write(b^0xff);
}
}

private String classDir;

@SuppressWarnings("deprecation")
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// TODO Auto-generated method stub
String classFileName = classDir+ "\\" + name + ".class";
byte[] bytes = null;
try {
FileInputStream fis = new FileInputStream(classFileName);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
cypher(fis, bos);
fis.close();
bos.close();
bytes = bos.toByteArray();
return defineClass(bytes, 0, bytes.length);
} catch (Exception e) {
e.printStackTrace();
}
//return defineClass(bytes, 0, bytes.length);
return super.findClass(name);
}

public MyClassLoader(){}
public MyClassLoader(String classDir){
this.classDir = classDir;
}
}


public class ClassLoaderTest {
public static void main(String[] args) throws Exception{
Class clazz = new MyClassLoader("itcast").loadClass("ClassLoaderAttachment");
Date d1= (Date) clazz.newInstance();//编译器不能加载ClassLoaderAttachment类所以用它的父类Date
System.out.println(d1);
}


}



4、类加载器的委托机制


每个ClassLoader本身只能分别加载特定位置的目录的类,但它们可以委托其他的类加载器去加载类,这就是类加载器的委托模式。类加载器一级级委托到BootStrap类加载,当BootStrap无法加载当前所要加载的类,然后才一级级回退到发起者类加载器去进行真正的加载。当回退到最初的类装载器时,如果它自己也不能完成类的装载,那就应报告ClassNotFoundException异常


当java虚拟机要加载一个类时,到底排除那个类加载器去加载呢?

1、首先当前线程的类加载器去加载线程中的第一个类;

2、如果类A中引用了类B,java虚拟机将使用类加载类A的类装载器来加载类B;

3、还可以直接调用MyClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。

1、当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,

不是再去找发起者类加载器的儿子,因为没有getChlid方法,即使有,那么多个儿子,找哪一个呢?

2、对着类加载器的层次机构和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因


有一道面试题,能不能自己写个类java.lang.System,为了不让我们写System类,类加载采用委托机制,这样可以保证爸爸们优先,

也就是总是使用爸爸们能找到的类,这样总是使用java系统提供的System,所以要避开类加载器的委托机制,自己写类加载器


---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IOS开发</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------


详细请查看:<a href="http://edu.csdn.net" target="blank">http://edu.csdn.net</a>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值