类加载器的概述:
1、 类加载器也是java类,因为其他的java类的类加载器本身也要被类加载器加载,显然必须由第一个类加载器不是java类,是BootStrap.嵌套在java虚拟机内核中,虚拟机内核启动就存在。可以加载别的类。包括别的类加载器。
2、 Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:
BootStrap、 ExtClassLoader、AppClassLoder
3、 Java虚拟机中的所有类加载器采用具有父子关系的树形结构进行组织,在实例化每个类加载器对象时,需要为其指定一个父类装载器对象或者默认采用系统类装载器为其父级类加载器。
类加载器间的关系及管辖范围:
类加载器的委托机制
加载类是到底派出哪个类加载器去加载?
1、首先当前线程的类加载器去加载线程中的第一个类。
2、如果类A中引用了类B,java虚拟机将使用加载类A的类加载器来加载类B。
3、还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
每个类加载器加载类时,又先委托给上一级类加载器。
当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不到类则抛ClassNotFoundExeption,不是再去找发起者类加载器的儿子,没有getChild方法。
编写自己的类加载器
1、 自定义的类加载器必须继承ClassLoader
2、 loadClass方法与findClass方法
3、 defineClass方法
模板方法设计模式
父类—>loadClass(流程)/findClass(覆盖)/得到了class文件转换成字节码—>definClass()
编写对class文件进行加密的工具类:
Import java.io.*
Public class MyClassLoader
{
Public static void main(String[] args) throws Exception
{
String srcPath =args[0];
String destDir =args[1];
FileInputStream fis = new FileInputStream(scrPath);
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^oxff);
}
}
}
Import java.util.Date;
Public class ClassLoaderAttachment extends Date
{
Public String toString()
{
Return “hello ,itcast”;
}<span style="font-family: 宋体;">}</span><p>/<span style="font-family: 宋体;">/</span><span style="font-family: 宋体;">有包名的类不能调用没包名的类。</span></p><p>//<span style="font-family:宋体;">复制完整的名称:把文件拖拽到命令行下即可;</span></p>
附注:
在工程下建立文件夹,把加密过的class文件放到此处。
在MyClassLoader下打开run对话框,设置运行的主类和传递的参数名。
在另一个类中ClassLoaderTest中
1·在ClassLoaderTest下打开run对话框,设置运行的主类(MyClassLoader)和传递的参数名
2·把加密生成的class文件覆盖ClassLoaderAttachment
3·ClassLoaderAttachment 对象并调用tostring方法。
编写和测试自己编写的解密器加载器
Import java.io.*
Public class MyClassLoader extends ClassLoader
{
Public static void main(String[] args) throws Exception
{
String srcPath =args[0];
String destDir =args[1];
FileInputStream fis = new FileInputStream(scrPath);
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^oxff);
}
}
Private String classDir;
@Override
Protected Class<?> findClass(String name) throws ClassNotFoundEception
//子类不能抛比父类更广泛的异常
{
String classFileNme = classDir+”\\”+name+”.class”;
Try
{
FileInputStream fis = new FileInputStream(classFileNme );
ByteArrayOutputStream bos = new ByteArrayOutputStream();
Cypher(fis,bos);
Fis.close();
Byte[] bytes=bos.toByteArray();
Return defineClass(bytes,0,bytes.length);//defineClass方法已过时
}
Catch(Exception e)
{
e.printStackTrace();
}
Return super.findClass(name);
}
Public MyClassLoader()
{}
Public MyClassLoader(String classDir)
{
this.classDir=classDir;
}
}
附注:
1·在ClassLoaderTest类中
Class clazz=new MyClassLoader(“itcstlib”).loadClass(“ClassLoaderAttachment ”);
Date d1=(Date)clazz.newInstance();
//ClassLoaderAttachment d1=(ClassLoaderAttachment )clazz.newInstance();
//在编译时期不能通过
System.out.print(d1);
2·删除classPath 目录下的ClassLoaderAttachment 不然在父类加载器中就已经加载了文件。
3·Class clazz=new MyClassLoader(“itcstlib”).loadClass(“ClassLoaderAttachment ”);
“ClassLoaderAttachment” -->cn.itcast.day2.ClassLoaderAttachment带包名
如果在带包名,如何用自己的加载器加载
Classclazz=new MyClassLoader(“itcstlib”).loadClass(“cn.itcast.day2.ClassLoaderAttachmen ”);
在MyClassLoader类中
String classFileNme = classDir+”\\”+name.substring(name..lastIndexOf(‘.’)+1)+”.class”