JAVA之CLASS、ClassLoader

1、CLASS

更多博客请访问本人自建网站

JAVA是一门面向对象的语言,每当程序生成一个实例的时候就会在堆里面开辟相应的空间来保存实例数据,堆中不会保存函数接口等信息,那么这些信息保存在哪里?JAVA针对每一个类别都会有一个单独的CLASS实例来保存。JAVA的枚举、类别、接口(注解也是一种接口)、基本数据类型都对应一个CLASS。数组类型对应据数组元素类型CLASS。

Class类包含了类的信息以及ClassLoader,因此可以通过Class类来生成该类的实例。如下代码所示,要生成一个String类的实例,需要首先获得String类的Class实例,通过Class.forname方法,并提供类的全名来获得Class。

Class clazz=Class.forName("java.lang.String");
String f=(String)clazz.newInstance();
f+="hello";
System.out.println(f);

CLASS类没有构造方法,因此不能人为地创建,只能通过ClassLoader在load Class文件的时候才会创建实例,每个Class对象都包含一个ClassLoader的引用,ClassLoader通过defineClass方法来创建一个Class实例。通常一个程序中,相同的CLASS类只会加载一次,因此相同的CLASS实例只有一个;判断CLASS实例是否是同一个当且仅当CLASS的name一样,而且所属的ClassLoader一样的时候。

2、ClassLoader

ClassLoader是JAVA中一个非常重要的概念,ClassLoader通过加装字节码生成CLASS实例,进而才能生成类实例。ClassLoader是有层级关系的:

如上图所示、Java虚拟机在启动时先加载BootstrapClassloader,其加载的路径为JRE\lib\rt.jar,直接使用解包工具可以看到rt.jar中包含的路径为:

可以看到J2SE中的大部分库都在这里加载,然后才是ExtensionClassLoader,其中包含了一下拓展库,最后加载的是AppClassLoader,用于加载用户定义的类。这几个加载器之间的层级关系如上图所示,该层级关系被称为双亲委托模型。使用双亲委托模型可以避免重复加载,即是当父加载器加载了某个类之后,子加载器就不会重复加载,这样比较安全。例如Bootstrap ClassLoader加载了String Class之后,自定义ClassLoader就不能再加载,否则恶意编码者就可以自定义类加载器来加载String的内容,这样做不安全。

3、自定义ClassLoader

用户自定义ClassLoader可以实现更多样化的功能,例如如果希望通过自定义方式加载自定义的类可以编写如下代码。

 

1) 首先定义一个测试类testClass

package test;
/**
 * Created by maitian13 on 2016/11/2.
 */
public class testClass{
    public void say(){
        System.out.println("I am a side class");
    }
}

2、自定义ClassLoader

编译之后生成该类的字节码,放到工程目录之外的某个目录下面,例如e:/out/testClass.class。默认的类加载器在没有将e:/out路径加入ClassPath的前提下是不会加载testClass类,我们需要自定义一个ClassLoader类(当然最简单的方式是加ClassPath)。自定义的类加载器必须重载findClass方法,ClassLoader在找不到类的时候会调用findClass方法。findClass方法需要调用defineClass方法来实例化Class对象,defineClass方法需要提供类的字节码以及类的名字,因此还需要一个读文件的方法getByte(),如果想要从网络上获得字节码,那么getByte()方法中就编写网络字节码获取代码即可。

import java.io.*;

/**
 * Created by maitian13 on 2016/11/2.
 */
public class MyClassLoader extends ClassLoader {
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        byte[] classData=getByte();
        Class clazz=defineClass(name,classData,0,classData.length);
        return clazz;
    }
    private byte[] getByte(){
        try {
            File file=new File("e://out//testClass.class");//字节码保存地址
            FileInputStream input=new FileInputStream(file);
            byte[] ans=new byte[1024*4];
            ByteArrayOutputStream out=new ByteArrayOutputStream();
            int len=-1;
            while((len=input.read(ans))!=-1){
                out.write(ans,0,len);
            }
            input.close();
            return out.toByteArray();
            //BufferedReader br=new BufferedReader(new FileReader(file));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

3、测试

下面使用自定义的ClassLoader,并验证一些理论。

public static void main(String... args) {
        try {
            ClassLoader loader=new MyClassLoader();
            ClassLoader loader2=new MyClassLoader();
            Class<?> c1=loader.loadClass("test.testClass");
            Class<?> c2=loader2.loadClass("test.testClass");
            Object o1=c1.newInstance();
            System.out.println(c1==c2);
            while (loader != null) {
                System.out.println(loader);
                loader = loader.getParent();
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


运行上述程序,得到的结果为:

false
MyClassLoader@511d50c0
sun.misc.Launcher$AppClassLoader@330bedb4
sun.misc.Launcher$ExtClassLoader@266474c2

第一行为false验证了,即使加载相同的类,使用不用的类加载器也会得到不同的Class实例。

第2~4行验证了双亲委托模型,唯一不同的是BootstrapClassLoader没有打印出来,这是因为BootstrapClassLoader是用c++编写的,在这里打印不出来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值