关闭

详述获取字节码文件及其内容的方法

标签: java字节码构造函数反射机制
516人阅读 评论(0) 收藏 举报
分类:

1 简述

Java 的反射机制是指:

  • 在运行状态中,对任意一个类(class文件),都能知道这个类的所有属性和方法;对任意一个对象,都能调用这个对象的方法和属性

简单点说,这种动态的获取信息和动态的调用对象的方法的功能就是 Java 的反射机制。利用 Java 的反射机制,我们可以很容易的获取类的详细信息,如构造函数、成员变量和成员函数等。

2 获取字节码文件

首先,构造一个实体类:

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午5:15
 * @Description Person Entity
 */
public class Person {
    private String name;
    private int age;

    public Person() {
        System.out.println("Person run");
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("Person param run ... " + this.name + " is " + this.age + " years old!");
    }

    public void showInfo(String name, int age){
        this.name = name;
        this.age = age;
        System.out.println("Show Peron Info : " + this.name + " is " + this.age + " years old!");
    }

    public void playBadminton(){
        System.out.println("Let's play badminton, go go go...");
    }
}

接下来,以 Person 类为例,演示获取字节码文件的 3 种方式:

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午5:23
 * @Description Get class file
 */
public class GetClassFile {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println("第 1 种获取方式:");
        getClassObject_1();
        System.out.println("第 2 种获取方式:");
        getClassObject_2();
        System.out.println("第 3 种获取方式:");
        getClassObject_3();
    }

    /**
     * 利用 Object 类中的 getClass 方法
     * 用这个方法时,必须明确具体的类,并创建对象
     * 比较麻烦
     */
    public static void getClassObject_1() {
        Person p = new Person();
        Class clazz = p.getClass();
        Person p1 = new Person("Charies",18);
        Class clazz1 = p1.getClass();
        System.out.println(clazz == clazz1);
    }

    /**
     * 任何数据类型都具备一个静态属性
     * 通过 .class 来获取对应的 Class 对象
     * 扩展性较差
     */
    public static void getClassObject_2() {
        Class clazz = Person.class;
        Class clazz1 = Person.class;
        System.out.println(clazz == clazz1);
    }

    /**
     * 通过给定的类的字符串名称就可以获取该类的字节码文件,更利于扩展
     * 可以用 Class 类中的 forName() 方法来完成
     */
    public static void getClassObject_3() throws ClassNotFoundException {
        // 包名一定要写全,否则会报 java.lang.ClassNotFoundException 异常
        String className = "Person";
        Class clazz = Class.forName(className);
        System.out.println(clazz);
    }
}

执行上述代码,结果如下图所示:

class

3 获取字节码文件的内容

3.1 获取构造函数

import java.lang.reflect.Constructor;

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午6:07
 * @Description Get class constructor
 */
public class GetClassConstructor {
    public static void main(String[] args) throws Exception {
        createNewObject_1();
        createNewObject_2();
    }

    /**
     * 获取默认构造函数
     */
    public static void createNewObject_1() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        String name = "Person";
        // 寻找该名称类文件,并加进内存,产生 Class 对象
        Class clazz = Class.forName(name);
        // 产生该类的实例对象(空参)
        Object obj = clazz.newInstance();
    }

    /**
     * 获取带参数的构造函数
     */
    public static void createNewObject_2() throws Exception {
        /**
         *  当获取指定名称对应类中的实体对象时,而且该对象的初始化不适用空参的构造函数
         *  可以先通过该类的字节码文件对象,获取空参的构造函数
         *  该方法为:getConstructor(parameterTypes)
         */

        // 包名一定要写全,否则会报 java.lang.ClassNotFoundException 异常
        String name = "Person";
        // 找寻该名称类文件,并加进内存,产生 Class 对象
        Class clazz = Class.forName(name);
        // 获取指定的构造函数对象
        Constructor constructor = clazz.getConstructor(String.class, int.class);
        // 通过该构造器对象的 newInstance 方法进行对象的初始化
        constructor.newInstance("Charies", 18);
    }
}

3.2 获取成员变量

import java.lang.reflect.Field;

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午6:15
 * @Description Get class field
 */
public class GetClassField {
    public static void main(String[] args) throws Exception {
        getField();
    }

    /**
     * 获取字节码文件中的成员变量
     */
    public static void getField() throws Exception {
        Class clazz = Class.forName("Person");
        Field field = null;
        // 获取本类字段,包含私有
        field = clazz.getDeclaredField("age");
        // 对私有字段的访问取消权限检查,可称之为暴力访问
        field.setAccessible(true);
        Object obj = clazz.newInstance();
        field.set(obj, Integer.valueOf(18));
        Object o = field.get(obj);
        System.out.println(o);
    }
}

3.3 获取成员函数

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * @Author Charies Guo
 * @Date 2017/7/29,下午6:22
 * @Description Get class method
 */
public class GetClassMethod {
    public static void main(String[] args) throws Exception {
        System.out.println("第 1 个方法:");
        getMethod_1();
        // System.out.println("第 2 个方法:");
        // getMethod_2();
        // System.out.println("第 3 个方法:");
        // getMethod_3();
    }

    /**
     * 获取指定 Class 中的公有函数
     */
    public static void getMethod_1() throws Exception {
        Class clazz = Class.forName("Person");

        // 获取的都是类中的公有方法
        Method[] methods = clazz.getMethods();

        // 获取本类中的所有方法
        methods = clazz.getDeclaredMethods();
        Method[] var5 = methods;
        int var4 = methods.length;

        for (int var3 = 0; var3 < var4; ++var3) {
            Method method = var5[var3];
            System.out.println(method);
        }
    }

    /**
     * 获取指定 Class 中的空参函数
     */
    public static void getMethod_2() throws Exception {
        Class clazz = Class.forName("Person");
        // 获取空参数的方法
        Method method = clazz.getMethod("playBadminton");
        Constructor constructor = clazz.getConstructor(new Class[]{String.class, Integer.TYPE});
        Object obj = constructor.newInstance(new Object[]{"Charies", Integer.valueOf(18)});
        method.invoke(obj, (Object[]) null);
    }

    /**
     * Integer.TYPE 等价于 int.class
     */
    public static void getMethod_3() throws Exception {
        Class clazz = Class.forName("Person");
        Method method = clazz.getMethod("showInfo", new Class[]{String.class, Integer.TYPE});
        Object obj = clazz.newInstance();
        method.invoke(obj, new Object[]{"Charies", Integer.valueOf(18)});
    }
}
1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:271020次
    • 积分:6235
    • 等级:
    • 排名:第4009名
    • 原创:210篇
    • 转载:62篇
    • 译文:5篇
    • 评论:475条
    博主的 GitHub 账号
    GitHub : Charies Gavin

        欢迎大家在 GitHub 上Follow 博主,以及 Fork、Star、Watch 博主的项目。


      青春不老 奋斗不止


      好学若饥虚心若愚
    博客专栏