Java反射机制,实现任意位置的class文件的解析

Wesley13
• 阅读 630

      之前一直在想如何读取一个class文件,并且获取其中的信息,Java有自己的_ClassLoader_ ,可以加载系统需要的class文件,或者用户自定义的class文件,但是对目录要求较高,需要时在classpath下,但是能不能将任意位置的class文件加载呢。

     class文件是以二进制流的方式存在磁盘文件上的,ClassLoader也肯定是在二进制文流读到内存中去的。终于找到在ClassLoader类中存在一个  

defineClass(String name, byte[]b,int off,int len);

方法,

         其中: String name  指的是类名,是一个完整的带包名的类名,如果不知道,可以使用 null 

                     byte []b 就是class文件的字节流 ,关键的东东啊

                     int  off    也就是起始位置 , len  读取的字节长度了,很好理解啊

 因为defineClass 是受保护的方法,不能直接访问,那么我们写一个方法继承自ClassLoader 是不是就 OK了呢?

        实现步骤:

          自定义Loader 

package com.jokingus.cls;

import java.io.FileInputStream;

public class Loader extends ClassLoader{

    static int maxsize=10000;
    
    public Class<?> load(String namefile,String className) throws Exception{
        
        Class<?> ctmp=    this.findLoadedClass(className);
        //查看class是否已经被加载了
        if(ctmp!=null){
            System.out.println("class文件已经被加载了");
            return ctmp;
        }
        
        FileInputStream in=new FileInputStream(namefile);
        byte[] classbyte=new byte[maxsize];
        int readsize;
        readsize=in.read(classbyte);
        System.out.println("readsize:"+readsize);
        in.close();
        
        return defineClass(null, classbyte, 0,readsize);
    }
    
}

   测试代码:

package com.jokingus.cls;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Test {

    public void parseMethod(Class<?> cls) {
        Method[] methods = cls.getDeclaredMethods();
        for (Method m : methods) {
            System.out.println(Modifier.toString(m.getModifiers()));
            Class<?> returnType = m.getReturnType();
            System.out.println(returnType.getName());

            Class<?>[] parameterTypes = m.getParameterTypes();
            for (Class<?> clas : parameterTypes) {

                String parameterName = clas.getName();
                System.out.println("参数名称:" + parameterName);
            }
            System.out.println(m.getName());
            System.out.println("\n****************");

        }
    }

    public void parseDeclaration(Class<?> cls) {
        Field[] fields = cls.getDeclaredFields();
        for (Field f : fields) {
            System.out.print(Modifier.toString(f.getModifiers()) + " ");
            System.out.print(f.getGenericType().toString() + " ");
            System.out.print(f.getName() + " = ");
            try {
                f.setAccessible(true);
                System.out.println(f.get(f.getGenericType()));
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            System.out.println();
        }
    }

    public void parseAnnotation(Class<?> cls) {
        Annotation[] annos = cls.getAnnotations();
        for (Annotation anno : annos) {
            System.out.println(anno.toString());
            Class<?> types = anno.annotationType();
            System.out.println(types.getName());
        }
    }

    public static void main(String[] args) throws Exception {
        Test t = new Test();
        Loader loader = new Loader();
        String namefile = "E:/Eclipse/IO/bin/com/wang/bytemodel/FileDemo.class";
        namefile = "E:/wangming/maven/high/target/classes/com/jokingus/dbutils/DBPool.class";
        namefile = "E:/wangming/maven/high/target/classes/com/jokingus/anno/SayHello.class";
        Class<?> c = loader.load(namefile, null);
        System.out.println(c.getName());
        String className = c.getName();

        // t.parseMethod(c);
        System.out.println("--------------------------------------");
        t.parseDeclaration(c);
        System.out.println("--------------------------------------");
        t.parseAnnotation(c);
        
        // loader.load(namefile,className);
    }

}

      保证namefile 为你的电脑上实际存在的一个 class文件,只要路径不错,应该就没有什么问题了。

       祝成功!!!

点赞
收藏
评论区
推荐文章
灯灯灯灯 灯灯灯灯
3年前
图文详解,史上最全【类加载子系统】解说!!
内存结构概述简图详细图英文版中文版注意:方法区只有HotSpot虚拟机有,J9,JRockit都没有如果自己想手写一个Java虚拟机的话,主要考虑哪些结构呢?1.类加载器2.执行引擎类加载器子系统类加载器子系统作用:1.类加载器子系统负责从文件系统或者网络中加载Class文件,class文件在文件开头有特定的文件标识。2.ClassLo
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java的class文件格式
\Java\深入理解JavaClass文件格式(一)(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fszwangdf%2Farticle%2Fdetails%2F25612445)(https://www.oschina.net/acti
Stella981 Stella981
3年前
ClassLoader解惑
一、什么是Classloader    一个Java程序要想运行起来,首先需要经过编译生成.class文件,然后创建一个运行环境(jvm)来加载字节码文件到内存运行,而.class文件是怎样被加载中jvm中的就是JavaClassloader所做的事情。    那么.class文件什么时候会被类加载器加载到j
Wesley13 Wesley13
3年前
Java 读取Properties文件时应注意的路径问题
1\.使用Class的getResourceAsStream()方法读取Properties文件(资源文件)的路径问题:      InputStreaminthis.getClass().getResourceAsStream("资源Name");    注意:    (1)这种方式要求Properties资源文件必须与当
Stella981 Stella981
3年前
Android动态加载之ClassLoader详解
Dalvik虚拟机如同其他Java虚拟机一样,在运行程序时首先需要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载可以从class文件中读取,也可以是其他形式的二进制流。因此,我们常常利用这一点,在程序运行时手动加载Class,从而达到代码动态加载执行的目的。只不过Android平台上虚拟机运行的是Dex字节码,一种对class文件优化的产物
Wesley13 Wesley13
3年前
Java基础之反射(非常重要)
反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))一、反射的概述JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法
Wesley13 Wesley13
3年前
Java反射技术概述
1.什么是Java反射?  就是正在运行,动态获取这个类的所有信息2.反射机制的作用  a.反编译:.class.java  b.通过反射机制,访问Java对象的属性,方法,构造方法等3.反射机制的应用场景  Jdbc加载驱动  SpringIOC实现  Java框架4.创建对象的两种方式  a.直
Stella981 Stella981
3年前
JVM概述和类装载器
1.JVM是运行在操作系统之上的,与硬件没有半毛钱关系。2.我就不用说jvm是什么意思,接下来我来说我对jvm的理解3.双亲委派机制4.ClassLoader负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由ExecutionEngine决定!
Wesley13 Wesley13
3年前
Java程序运行原理分析
class文件内容class文件包含Java程序执行的字节码数据严格按照格式紧凑排列在class文件的二进制流,中间无分割符文件开头有一个0xcafebabe(16进制)特殊的标志!img(https://gitee.com/mosedefeng/notes/raw/master/images/1.1.1