zoukankan      html  css  js  c++  java
  • 用.class文件创建对象

    第一步:  给你一个编译好的class文件以及它的包名,创建一个对象出来。

          1)class文件源代码

          

    Java代码  收藏代码
    1. package com.wsc.classloader;  
    2.   
    3. public class Tool{  
    4.   
    5.     public void print() {  
    6.     }  
    7. }  

        2)使用javac Tool.java 编译成class文件

        3)将Tool.class文件读取到内存中,生成byte[]数组

        

    Java代码  收藏代码
    1. /** 
    2.  * 加载class文件 
    3.  *  
    4.  * @param clazzPath 
    5.  *            class绝对文件路径 
    6.  * @return 字节数组 
    7.  * @throws IOException 
    8.  */  
    9. private byte[] loadClassFile(String clazzPath) throws IOException {  
    10.     FileInputStream fis = new FileInputStream(clazzPath);  
    11.     BufferedInputStream bis = new BufferedInputStream(fis);  
    12.     ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    13.   
    14.     byte[] buffer = new byte[1024 * 256];  
    15.     int ch = 0;  
    16.     while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {  
    17.         baos.write(buffer, 0, ch);  
    18.     }  
    19.     return baos.toByteArray();  
    20. }  

          4)自定义ClassLoader,使用ClassLoader中的defineClass方法:protected final Class<?> defineClass(String name, byte[] b, int off, int len)。参数分别是类名称,class文件对应的字节数组,起始位置和终止位置。

         

    Java代码  收藏代码
    1. @Override  
    2. protected Class<?> loadClass(String name, boolean resolve)  
    3.         throws ClassNotFoundException {  
    4.     Class<?> c = findLoadedClass(name);  
    5.     if (c == null) {  
    6.         c = defineClass(name, data, 0, data.length);  
    7.     }  
    8.     return c;  
    9. }  

     整体代码是:

    Java代码  收藏代码
    1. package com.wsc.classloader;  
    2.   
    3. import java.io.BufferedInputStream;  
    4. import java.io.ByteArrayOutputStream;  
    5. import java.io.FileInputStream;  
    6. import java.io.IOException;  
    7.   
    8. public class ClassLoaderOne extends ClassLoader {  
    9.   
    10.     public static void main(String[] args) throws Exception {  
    11.   
    12.         ClassLoaderOne loader = new ClassLoaderOne(  
    13.                 "E:\JAVA\JAVAFX\ClassLoader\libs\Tool.class");  
    14.         Class<?> clazz = loader.loadClass("com.wsc.classloader.Tool");  
    15.         Object o = clazz.newInstance();  
    16.         System.out.println(o.getClass().getClassLoader());  
    17.   
    18.     }  
    19.   
    20.     private byte[] data;  
    21.   
    22.     public ClassLoaderOne(String clazzPath) throws IOException {  
    23.         data = loadClassFile(clazzPath);  
    24.     }  
    25.   
    26.     /** 
    27.      * 加载class文件 
    28.      *  
    29.      * @param clazzPath 
    30.      *            class绝对文件路径 
    31.      * @return 字节数组 
    32.      * @throws IOException 
    33.      */  
    34.     private byte[] loadClassFile(String clazzPath) throws IOException {  
    35.         FileInputStream fis = new FileInputStream(clazzPath);  
    36.         BufferedInputStream bis = new BufferedInputStream(fis);  
    37.         ByteArrayOutputStream baos = new ByteArrayOutputStream();  
    38.   
    39.         byte[] buffer = new byte[1024 * 256];  
    40.         int ch = 0;  
    41.         while ((ch = bis.read(buffer, 0, buffer.length)) != -1) {  
    42.             baos.write(buffer, 0, ch);  
    43.         }  
    44.         return baos.toByteArray();  
    45.     }  
    46.   
    47.     @Override  
    48.     protected Class<?> loadClass(String name, boolean resolve)  
    49.             throws ClassNotFoundException {  
    50.         Class<?> c = findLoadedClass(name);  
    51.         if (c == null) {  
    52.             c = defineClass(name, data, 0, data.length);  
    53.         }  
    54.         return c;  
    55.     }  
    56.   
    57. }  

     感觉是这样的,跑一下:

    Java代码  收藏代码
    1. Exception in thread "main" java.lang.SecurityException: Prohibited package name: java.lang  
    2.     at java.lang.ClassLoader.preDefineClass(Unknown Source)  
    3.     at java.lang.ClassLoader.defineClass(Unknown Source)  
    4.     at java.lang.ClassLoader.defineClass(Unknown Source)  
    5.     at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52)  
    6.     at java.lang.ClassLoader.loadClass(Unknown Source)  
    7.     at java.lang.ClassLoader.defineClass1(Native Method)  
    8.     at java.lang.ClassLoader.defineClass(Unknown Source)  
    9.     at java.lang.ClassLoader.defineClass(Unknown Source)  
    10.     at com.wsc.classloader.ClassLoaderOne.loadClass(ClassLoaderOne.java:52)  
    11.     at java.lang.ClassLoader.loadClass(Unknown Source)  
    12.     at com.wsc.classloader.ClassLoaderOne.main(ClassLoaderOne.java:14)  

       意思是:禁止加载名为java.lang的包。

       原因是:虽然Tool类中没有使用任何引入java.lang下类,但是它的父类Object是在java.lang下的,classloader加载Tool类时会把它所有的关系网都加载出来才行,父类Object肯定是要加载的。

       这样就简单了!无非多写一个If else.使用父加载器(类加载器都有一个父类加载器)加载即可。

      

    Java代码  收藏代码
    1. @Override  
    2. protected Class<?> loadClass(String name, boolean resolve)  
    3.         throws ClassNotFoundException {  
    4.     Class<?> c = findLoadedClass(name);  
    5.     if (name.equals("java.lang.Object")) {  
    6.         ClassLoader parent = getParent();  
    7.         c = parent.loadClass(name);  
    8.     }  
    9.     if (c == null) {  
    10.         c = defineClass(name, data, 0, data.length);  
    11.     }  
    12.     return c;  
    13. }  

       跑一下结果是:

      

    Java代码  收藏代码
    1. com.wsc.classloader.ClassLoaderOne@ca470  

      第二步:新的问题

        

    Java代码  收藏代码
    1. Method[] methods = clazz.getMethods();  
    2. for (int i = 0; i < methods.length; i++) {  
    3.     String name = methods[i].getName();  
    4.     System.out.println(name);  
    5.     Class<?>[] params = methods[i].getParameterTypes();  
    6.     for (int j = 0; j < params.length; j++) {  
    7.         System.out.println(params[j].toString());  
    8.     }  
    9. }  

       这个时候还是会报刚才的错误,因为Method类也在java.lang包下,只能在增加一个If else.

       显然,代码应该这样写

       

    Java代码  收藏代码
    1. @Override  
    2. protected Class<?> loadClass(String name, boolean resolve)  
    3.         throws ClassNotFoundException {  
    4.     Class<?> c = findLoadedClass(name);  
    5.     if (c == null) {  
    6.         // 如果父加载器不为null,使用父类加载器加载(比如Object,HashMap等核心类)  
    7.         if (getParent() != null) {  
    8.             try {  
    9.                 c = getParent().loadClass(name);  
    10.             } catch (Exception e) {  
    11.                 // 父类可能没加载,则抛异常  
    12.             }  
    13.   
    14.         }  
    15.         // 如果父类加载器没有加载,再使用自定义加载器加载  
    16.         if (c == null) {  
    17.             c = defineClass(name, data, 0, data.length);  
    18.         }  
    19.     }  
    20.   
    21.     return c;  
    22. }  

       打印结果:

      

    Java代码  收藏代码
    1. toString  
    2. print  
    3. class java.lang.String  
    4. getClass  
    5. hashCode  
    6. equals  
    7. class java.lang.Object  
    8. notify  
    9. notifyAll  
    10. wait  
    11. long  
    12. int  
    13. wait  
    14. wait  
    15. long  
    16. com.wsc.classloader.ClassLoaderOne@fcfa52  

       第三步:如果本地可以通过.class文件创建,远程当然也已同一个道理(如果需要加密,在本地多一个解密即可)。如果class文件是远程调用的话,本地一般使用接口或者反射两种方法调用。首选是接口,反射一是效率,而是要清楚所有的方法名称、参数名称过于麻烦。

      由于远程加载class文件到本地,如果出错很难定位出错位置。幸好,classloader使用规则默认是根据URLClassLoader来使用的,会先根据检查本地是否有该类,所以可以直接将源码放在本地即可调试,当然发布的时候一定要删除。

       如图:

        通过这个基本的入门程序可以了解ClassLoader的基本流程。
        

       1

  • 相关阅读:
    “XXXXX” is damaged and can’t be opened. You should move it to the Trash 解决方案
    深入浅出 eBPF 安全项目 Tracee
    Unity3d开发的知名大型游戏案例
    Unity 3D 拥有强大的编辑界面
    Unity 3D物理引擎详解
    Unity 3D图形用户界面及常用控件
    Unity 3D的视图与相应的基础操作方法
    Unity Technologies 公司开发的三维游戏制作引擎——Unity 3D
    重学计算机
    windows cmd用户操作,添加,设备管理员组,允许修改密码
  • 原文地址:https://www.cnblogs.com/yamagl/p/3885356.html
Copyright © 2011-2022 走看看