黑马程序猿——Java中的类载入器

简介:

------- android培训java培训、期待与您交流!

--------

类载入器

Java虚拟机中能够安装多个类载入器,系统默认三个主要类载入器,每一个类负责载入特定位置的类:

BootStrap      ExtClassLoader     AppClassLoader

 

类载入器有什么作用?

当程序须要的某个类,那么须要通过类载入器把类的二进制载入到内存中,类载入器也是Java类

 

类载入器也是java类,由于其它是java类的类载入器本身也要被类载入器载入。显然必须有第一个类载入器不是java类。这正是BootStrap

 

Java虚拟机中的全部类载入器採用具有父子关系的树型结构进行组织。在实例化每一个类载入器对象时,须要为其指定一个父级类载入器对象或者默认採用系统类载入器为其父级类载入器。

 

类载入器的托付机制:

当java虚拟机要载入一个类时,究竟派出哪个类载入器去载入呢?

(1)  首先当前线程的类载入器去载入线程中的第一个类

(2)  假设类A中引用了类B,java虚拟机将使用载入类A装载器来载入类B

(3)  还能够直接调用ClassLoader.loadClass()方法来指定某个类载入器去载入某个类

面试题:能不能自己写个类java.lang.System?

     通常不能够写。由于类载入器採用托付机制,这样保证了父类优先,也就是说总是使用父类能找到的类,这样总是使用java系统提供的System

 

编写自己的类载入器

知识解说:

(1)  自己定义的类载入器必须继承ClassLoader

(2)  覆写loadClass()方法下的findClass方法,由于要保留loadClass中的机制

(3)  defineClass方法

编程步骤:

(1)  编写一个对文件内容进行简单加密的程序

(2)  编写一个自己的类载入器,可实现对加密过的类进行装载和解密

(3)  编写一个程序调用类载入器载入类。在源程序中不能用该类名定义引用变量,由于编译器无法识别这个类。

程序中能够除了使用ClassLoader。load方法之外,还能够使用设置线程的上下文类载入器或者系统类载入器,然后再使用Class.forName

实验步骤:

(1)  对不带包名的class文件进行加密。加密结果存放到另外一个文件夹,比如,java MyClassLoader MyTest.class F:\itcast

(2)  执行载入类的程序,结果可以被正常载入,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast

(3)  用加密后的类文件替换CLASSPATH环境下的类文件,再运行上一步操作就出问题了,错误说明是AppClassLoader类载入器装载失败

(4)  删除CLASSPATH环境下的类文件,再运行上一步操作就没问题了

 

编写自己的类载入器

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

        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();

    }

 /**

     * 加密方法,同一时候也是解密方法

     * @param ips

     * @param ops

     * @throws Exception

     */

    private static void cypher(InputStream ips ,OutputStream ops) throws Exception{

        int b = -1;

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

            ops.write(b ^ 0xff);//假设是1就变成0,假设是0就变成1

        }

    }

然后在新建一个类,通过上面的方法将新建的类的字节码进行加密:

public class ClassLoaderAttachment extends Date {

    public String toString(){

        return "hello,itcast";

    } 

}

那么这就须要使用我们自己的类载入器来进行解密了.

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(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);//假设是1就变成0,假设是0就变成1

        }

    }

 

    private String classDir;

 

    @Override

    protected Class<?> findClass(String name) throws ClassNotFoundException {

        String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.')+1) + ".class";

        try {

            FileInputStream fis = new FileInputStream(classFileName);

            ByteArrayOutputStream bos = new ByteArrayOutputStream();

            cypher(fis,bos);

            fis.close();

            System.out.println("aaa");

            byte[] bytes = bos.toByteArray();

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

        } catch (Exception e) {

            e.printStackTrace();

        }

        return null;

    }

 

    public MyClassLoader(){

    }

 

    public MyClassLoader(String classDir){

        this.classDir = classDir;

    }

}

測试执行代码:

 

        Class clazz = new MyClassLoader("myClass").loadClass("ClassLoaderAttachment");

        //此处不能在使用ClassLoaderAttachment由于一旦用了之后,

        //系统的类载入器就会去载入,导致失败,所以该类就继承了Date类了.

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

        System.out.println(date);

执行结果:

 

------- android培训java培训、期待与您交流!




本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5328697.html,如需转载请自行联系原作者

相关文章
|
5天前
|
Java 关系型数据库 MySQL
Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
【4月更文挑战第12天】Elasticsearch【问题记录 01】启动服务&停止服务的2类方法【及 java.nio.file.AccessDeniedException: xx/pid 问题解决】(含shell脚本文件)
33 3
|
1天前
|
人工智能 安全 Java
Java8 - LocalDateTime时间日期类使用详解
Java8 - LocalDateTime时间日期类使用详解
|
2天前
|
安全 Java 程序员
|
3天前
|
Java
Java Class类
Java Class类
8 0
|
9天前
|
Java 编译器
Java Character 类
4月更文挑战第13天
|
10天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
14天前
|
Java Shell
Java 21颠覆传统:未命名类与实例Main方法的编码变革
Java 21颠覆传统:未命名类与实例Main方法的编码变革
13 0
|
14天前
|
Java
Java 15 神秘登场:隐藏类解析未知领域
Java 15 神秘登场:隐藏类解析未知领域
17 0
|
16天前
|
安全 Java
append在Java中是哪个类下的方法
append在Java中是哪个类下的方法
23 9
|
16天前
|
JavaScript Java 测试技术
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)
30 0
基于Java的网络类课程思政学习系统的设计与实现(源码+lw+部署文档+讲解等)