`
黑暗天使
  • 浏览: 94928 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

在运行时刻从文件中调入Class

    博客分类:
  • java
 
阅读更多

前言:

了解Java的类装载器:


Java 编程语言编译器把源代码代码转换成为一个假定机器(即虚拟机)上的 机器语言。虚拟机代码保存在一个后缀为.class的类文件中。每个类文件保存这 
个类的所有方法的虚拟机代码。


当运行时用一个解释程序解释这些类文件,把这些文件内的虚拟机指信信令翻 译成本地的机器语言,分存内存,确定程序入口点。


类装载器功能类似与C中调入dll文件文法,在C中是调入dll文件分配内存,确定 程序入口点(分配入口指针),而在java中调入一个class文件,同样是从本地或网络 
中调入文件,转换为本地机器代码,分配内存,确定程序入口点。


当我们在使用中有时要使用一个新类,知道它的文件路径和它的文件名字,我们 要把它调入系统并使用它或者说一个类文件已经被加密处理,类文件里面的内容 
是我们加密后的密文,不能直接使用,只能是对文件内容解密后才能使用,就可 以用类库加载器ClassLoader,把类文件当做数据流读入到一个byte[]中,对 
这个 byte[]进行解密处理后(没加密当然就不用做这步了),再通过 byte[] 生成一个类,并加载到系统中。


对于使用中有以下两种方法: 


  1. 方法1

    使用接口类,新调用的class是对它的具体实现 

    1) 写一个接口类 newface.class 







    public interface newface {
    public void out(String xx);
    public int outsize(String x1,String x2);
    }


     


    2) 写接口文件实现 testfacea.class 并更名为 testfacea.file 或其它文件名全可以 







    /*
    newface的实现
    */
    public class testfacea implements newface{
    public void out(String xx) {
    System.out.println(xx+" for testfacea ");
    }
    public int outsize(String x1,String x2) {
    return x1.length()+x2.length();;
    }
    }


    执行的的命令

    javac testfacea.java

    ren testfacea.class testfacea.file

     


    3) 在主程序中调入文件到byte[]中,可以在文件可以在本地,也可用网络无论如何只要能将编译后的文件内容的类代码放到 byte[]当中就可以


    java.io.FileInputStream in=new java.io.FileInputStream(namefile);


    byte[] classbyte=new byte[maxsize];


    4) 转换成一个Class并初始化


    return defineClass(classname,classbyte,0,readsize);


    5) 实现接口

    实际上就是对一个接口类用调入的文件实现,当然可以用不同的文件进行不同的实现也可以对一个文件进行加解密操作, 







    //方法 1 的例子代码,newface是本地接口类,newface.class本地已经存在 开始
    testc=cl.load("testfacea.file","testfacea");
    testo=testc.newInstance();
    ((newface)testo).out("方法1 第(1)种使用方法");
    System.out.println("outsize="+((newface)testo).outsize("1111","aaaa"));


    testc=cl.load("testfacea.fisle","testfacea");
    testo=testc.newInstance();
    newface newface1=(newface)testo;
    newface1.out("方法1 第(2)种使用方法");
    System.out.println("outsize="+newface1.outsize("22222","bbbbb"));


     


    要注意的是对一个要调入的文件,一定要是一个已经存在的接口类的实现这个有点EJB中的调用的中远程接口要在本地,而调入的文件就是EJBobject了这种方法的的好处是要调入的class中的方法是可以说是已知的,相对来讲这种方法简明易用以下是主程序的完整代码 







    //使用的主程序
    public class testnewface {
    public static void main(String[] args) throws java.lang.Exception
    {
    // 共用初使化参数,开始
    Class testc;
    Object testo;
    cloader cl=new cloader();
    // 共用初使化参数,结束

    //方法 1 的例子代码,newface是本地接口类,newface.class本地已经存在 开始
    testc=cl.load("testfacea.file","testfacea");
    testo=testc.newInstance();

    ((newface)testo).out("方法1 第(1)种使用方法");
    System.out.println("outsize="+((newface)testo).outsize("1111","aaaa"));

    testc=cl.load("testfacea.fisle","testfacea");
    testo=testc.newInstance();
    newface newface1=(newface)testo;
    newface1.out("方法1 第(2)种使用方法");
    System.out.println("outsize="+newface1.outsize("22222","bbbbb"));
    //方法 1 的例子代码,结束
    }
    }
    /*
    要想自己完成从一个 byte[] 转换到一个Class 必须要 extends ClassLoader
    因为ClassLoader中的方法defineClass是 protected 要使用只有 extends ClassLoader
    */
    class cloader extends ClassLoader {
    static int maxsize=10000;
    public Class load(String namefile,String classname) throws java.lang.Exception
    {
    try {
    //进行判断这个class是否已经调入,已经有就直接返回,不然就调入
    Class ctmp=this.findLoadedClass(classname);
    System.out.println(ctmp.getName()+" is load");
    return ctmp;
    }
    catch (Exception e) {
    //System.out.println(e);
    }
    java.io.FileInputStream in=new java.io.FileInputStream(namefile);
    byte[] classbyte=new byte[maxsize];
    //实际应用时完全可以对一个文件进行加解密处理,只要保证使用defineClass时classbyte中
    //已经解密后的内容就可以
    int readsize;
    readsize=in.read(classbyte);
    // System.out.println("读文件长:"+readsize);
    in.close();
    return defineClass(classname,classbyte,0,readsize);
    }
    }


     


  2. 方法2

    不使用本地接口类的方法,这种方法class从文件定义成一个class和方法1是相同的,但要使用这个class就不同了,这种方法不需要接口类, 

    1) 写一个类 testfacea.class (本例中为了方便还是使用了testfacea,实际上已经可以不用 implements 
    newface,即可以完全不用接口类) 







    public class testfacea {
    public void out(String xx) {
    System.out.println(xx+" for testfacea ");
    }
    public int outsize(String x1,String x2) {
    return x1.length()+x2.length();;
    }
    }


     


    为明析起见还有一个测试用类型:一个列系统信息表的类 







    public class listinfo {
    public static void main(String[] args) {
    //列系统信息表 begin
    String skey,sinfo;
    Object so;
    java.util.Enumeration hlistkey=System.getProperties().propertyNames();
    while (hlistkey.hasMoreElements())
    {
    skey=(String)hlistkey.nextElement();
    so=System.getProperty(skey);
    System.out.println("key="+skey+" info="+so);
    }
    //列系统信息表 end
    }
    }


     


    2) 生成 testfacea.class 更名为 testfacea.file 或其它文件名也可以


    生成 listinfo.class 更名为 listinfo.file 或其它文件名也可以


    执行的的命令


    javac testfacea.java


    ren testfacea.class testfacea.file


    javac listinfo.java


    ren listinfo.class listinfo.file


    3) 主程序中调入文件到byte[]中,可以在本地文件调用,也可用网络无论如何只要能将编译后的文件内容的类代码放到 byte[]当中就可以


    java.io.FileInputStream in=new java.io.FileInputStream(namefile);


    byte[] classbyte=new byte[maxsize];


    4) 转换成一个Class


    return defineClass(classname,classbyte,0,readsize);


    5)如果调用的方法不是static,那么要初始化一个 Object


    6) 用java.lang.Class 中的 getMethod(方法名,Class 类型的参数数组) 得到一个


    java.lang.reflect.Method 就是说从一个class取到它的方法后调用这个方法


    7 ) 使用java.lang.reflect.Method 中的 invoke(Object,new Object[]{参数1,参数2,...}) 
    调用方法,invoke 返回一个Object,Object 的实际就是相应方法的返回类型,如果调用的方法不是static,那么Object 
    就放入初始化一个的Object,否则放一个 null 值


    8) 转换相应的类型到正确对应的Class


    本方法要在写程序时已知要调入的class中的方法名,参数,返回类型和相应功能,相对来讲复杂一些


    主程序代码: 







    */

    //使用的主程序
    public class testnewface {
    public static void main(String[] args) throws java.lang.Exception
    {
    // 共用初使化参数,开始
    Class testc;
    Object testo;
    cloader cl=new cloader();
    // 共用初使化参数,结束

    //方法 2 的例子代码,开始
    testc=cl.load("testfacea.fisle","testfacea");
    testo=testc.newInstance();

    String x="方法2 第(1)种使用方法--进行 Instance";
    java.lang.reflect.Method mout=testc.getMethod("out",new Class[]{x.getClass()});
    System.out.println("mout name="+mout.getName());
    mout.invoke(testo,new Object[]{x});

    String x1="33333",x2="cccccc";
    java.lang.reflect.Method moutsize=testc.getMethod("outsize",new Class[]{x1.getClass(),x2.getClass()});
    System.out.println("mout name="+moutsize.getName());
    Integer xx=(Integer)moutsize.invoke(testo,new Object[]{x1,x2});
    System.out.println(xx.intValue());

    //方法(2) 不进行Instance,---调用了另外一个有main的类
    testc=cl.load("listinfo.file","listinfo");
    System.out.println("testc="+testc.getName());
    java.lang.reflect.Method m=testc.getMethod("main",new Class[]{args.getClass()});
    System.out.println("m="+m.getName());
    m.invoke(null,new Object[]{args});
    //方法 2 的例子代码,结束
    }

    }

    /*
    要想自己完成从一个 byte[] 转换到一个Class 必须要 extends ClassLoader
    因为ClassLoader中的方法defineClass是 protected 要使用只有 extends ClassLoader
    */

    class cloader extends ClassLoader {
    static int maxsize=10000;
    public Class load(String namefile,String classname) throws java.lang.Exception
    {

    try {
    //进行判断这个class是否已经调入,已经有就直接返回,不然就调入
    Class ctmp=this.findLoadedClass(classname);
    System.out.println(ctmp.getName()+" is load");
    return ctmp;
    }
    catch (Exception e) {
    //System.out.println(e);
    }
    java.io.FileInputStream in=new java.io.FileInputStream(namefile);
    byte[] classbyte=new byte[maxsize];
    //实际应用时完全可以对一个文件进行加解密处理,只要保证使用defineClass时classbyte中
    //已经解密后的内容就可以
    int readsize;
    readsize=in.read(classbyte);
    // System.out.println("读文件长:"+readsize);
    in.close();
    return defineClass(classname,classbyte,0,readsize);
    }
    }


     



小结: 

但是Java并不提供一个类似于类库卸载器(ClassUnloader) 的功能,能够把已经装载的模块从内存里面清除掉。所以如果一个class已经调入,就放在了内存当中,并在程序信息表内记录本class已经调入,如果再一次使用就从内存当中调入,如果实际文件更新也只能是程序下次运行时间再调入,而不能在运行期间更新一个class,如果强行再一次调入就会 
Linkage Error: duplicate class definition (重复定义class) 所以在每次调用前用 findLoadedClass 
方法进行一下判断。

分享到:
评论

相关推荐

    实现文件的读写以及进度的保存和调入的VB程序

    本例可实现文件的读写以及进度的保存和调入。

    flash文本的调入

    在Flash中,文本的调入是一项重要的功能,它允许开发者从外部源动态加载文本和图片,从而实现内容的更新和交互性。动态文本是相对于静态文本的一种,它可以在运行时改变,提供更灵活的显示效果。自动生成滚动条则是...

    java实现类似金山练字的英文打字练习

    用java实现类似金山...从文件中调入英文录入材料,并将其显示 到图形界面的窗口中,然后根据用户的按键依次设置窗口中字符的颜色(正确为 12 绿色,错误为红色),用户打字结束后可以给出错误率,以及平均录入速度。

    参考资料-U9资产调入单单据类型.zip

    在企业信息化管理中,财务系统扮演着至关重要的角色,其中资产调入单是记录企业固定资产增减变动的重要凭证。本文将围绕"U9资产调入单单据类型"这一主题,深入探讨其在实际应用中的详细知识。 一、U9系统概述 U9是...

    调入调出人员情况表.doc

    “调入时间”和“调出时间”记录了员工在不同岗位上的起止日期,这些信息对于计算工龄、绩效评估和确定福利待遇都有实际意义。 “调入原因”和“调出原因”是理解人员调动背后逻辑的关键,可能涉及企业发展需求、...

    文件管理 4.1文件系统基础1

    目录结构在文件管理中起着关键作用,从单级目录到多级目录(树形结构),再到无环目录结构,都是为了满足用户按名存取、提高检索速度、控制访问权限以及解决文件重名等问题。文件控制块(FCB)和索引节点是实现目录...

    操作系统课设-文件管理系统

    一个操作系统文件管理的小课设,采用javafx做...文件管理,由于系统的内存有限并且不能长期保存,故平时总是把它们以文件的形式存放在外存中,需要时再将它们调入内存。如何高效的对文件进行管理是操作系统实现的目标。

    参考资料-U9库存调入单.zip

    参考资料-U9库存调入单.zip

    BAT批处理文件语法

    每个编写好的批处理文件都相当于一个DOS的外部命令,可以将它所在的目录放到DOS搜索路径(path)中来使得它可以在任意位置运行。 在DOS和Win9x/Me系统下,C:盘根目录下的AUTOEXEC.BAT批处理文件是自动运行批处理文件...

    acad文件导入GE,并生成kml文件

    将acad文件导入到Google Earth中,可以让设计者和工程师在真实世界背景下查看他们的设计,这在规划、景观设计、建筑模拟等方面非常有用。 为了实现这个功能,我们需要一个转换工具,从描述中的"acad2kml3.0"来看,...

    操作系统中文件管理部分

    用户和系统要频繁地对它们进行访问,如果让用户在程序中自己安排它们在外存的存放位置,不仅要求用户熟悉外存的特性、各种文件的属性以及它们在外存上的位置,而且在多用户环境下,还必须保证数据的安全性和一致性。

    DOS三个基本启动文件COMMAND.COM MS-DOS.SYS IO.SYS DOS引导文件Boot.rar sys.com

     系统硬盘中的MSDOS.SYS内容比较完整,包括必要的启动配置命令,文件长度必须大于1024 bytes,即占用两个以上磁盘扇区,这一要求在该文件中说明为保证兼容性,但从未见更深入的介绍,实际上文件小于1024 bytes对...

    VBA 自动调入数据

    VBA(Visual Basic for Applications)是Microsoft Office套件中的一种编程语言,用于自动化和自定义工作流程,特别是在Excel中。本主题将深入探讨如何利用VBA来实现Excel表之间的自动数据调入,这对于大量数据管理...

    C文件操作和解析

    - **文件存储位置**:文件通常存储在外部介质(如磁盘)上,使用时会被调入内存。 - **文件分类**: - **普通文件**:驻留在磁盘或其他外部介质上的有序数据集,包括源文件、目标文件、可执行程序等。 - **设备...

    经典BAT批处理文件语法教程及使用方法.doc

    可以将批处理文件放到dos的搜索路径中,使得它可以在任意位置运行。也可以将批处理文件放到一个特定的目录中,以便于管理和维护。 五、批处理文件的应用 批处理文件可以应用于各种场景,例如自动运行命令、设置...

    操作系统——文件系统PPT课件.pptx

    检索目录文件过程中只用到文件名,仅当找到一个目录项时才从该目录项中读出该文件的物理地址,而其它一些对该文件进行描述的信息在检索目录时不会用到,故这些信息不需调入内存。于是,可以将文件名和文件描述信息...

    沪深300指数成分股历年调整名单(2005-2023年) 调入和调出

    8日联合发布的反映沪深300指数编制目标和运行状况的金融指标,并能够作为投资业绩 的评价标准,为指数化投资和指数衍生产品创新提供基础条件。 公告日期:2005.4 .8-2023.12.11 包含字段 公告日期 变更日期 成份证券...

    bat文件编写语言

    在 DOS 和 Win9x/Me 系统下,C:盘根目录下的 AUTOEXEC.BAT 批处理文件是自动运行批处理文件,每次系统启动时会自动运行该文件,可以将系统每次启动时都要运行的命令放入该文件中,例如设置搜索路径,调入鼠标驱动和...

    求公交车站点的最短路径

    问题描述:一个城市有若干公交线路,一个公交线路中的相邻两个站点需要运行的时间是已知的,假设在所有公交线路中任意两个相邻站点之间的耗时都是相同的,计算任意两个站点的最小时间。 基本要求: (1)建立城市的...

Global site tag (gtag.js) - Google Analytics