关闭

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

标签: java字节码构造函数反射机制
888人阅读 评论(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
查看评论

字节码文件

1.字节码文件 1.1字节码文件的内部组成结构 每一个项(类结构格式的内容)包括类型、名称以及该项的数量。类型可以是表名,同时也是“基本类型”。在这个结构体中只有两种数据结构,分别是无符号和表,其中无符号数属于字节码文件中的“基本类型”,如下:字节码文件中的“基本类型” 1) ...
  • owen_william
  • owen_william
  • 2016-03-26 18:10
  • 564

jvm(6)-java类文件结构(字节码文件)

【0】README 0.1)本文部分文字描述转自 “深入理解jvm”,旨在学习 类文件结构  的基础知识; 0.2)本文荔枝以及荔枝的分析均为原创; 【1】类文件概述 1)各种不同平台的虚拟机与所有平台都统一使用存储格式——字节码,他是构成平台无关性的基石; 2)时至今日,商业机构和开...
  • PacosonSWJTU
  • PacosonSWJTU
  • 2016-03-27 20:25
  • 2286

黑马程序员----反射-获取字节码文件对象三种方式

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ------- JAVA反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象方法的功...
  • dantou7190
  • dantou7190
  • 2015-07-30 08:06
  • 2221

获取字节码文件的三种方式

在本文中,以Person类为例,将分别演示获取该类字节码文件的三种方式,其具体思想及代码如下所示:public class Person { private int age; private String name; public Person() { Syst...
  • qq_35246620
  • qq_35246620
  • 2016-12-12 07:10
  • 889

Java中获取类的字节码文件的三种方式

第一种方式:全类名的方式获取字节码文件 Class class2 = Class.forName("day27.Dog");//通过类名的全路径获取字节码文件 第二种方式:通过 类名.class 的方式获取字节码文件 Class class1 = Dog.class; //通过类...
  • u014143369
  • u014143369
  • 2016-10-19 21:49
  • 198

获取字节码文件对象的三种方式(反射机制)

1.写一个Person类,用于测试,如下 package com.bean; public class ReflectDemo { public static void main(String[] args) { getClassObject_3(); } /* * 获取字节码...
  • qq_37555897
  • qq_37555897
  • 2017-07-14 11:32
  • 108

Java字节码文件

字节码简介 编译器将Java源码编译成符合Java虚拟机规范的字节码文件。 字节码组成结构比较特殊,其内部不包含任何分隔符区分段落。 一组8位字节单位的字节流组成了一个完整的字节码文件。 字节码内部组成结构 《Java虚拟机规范 Java SE7》中,每一个字节码文件都对应着全局唯一的一个类或者接口...
  • chenzhao2013
  • chenzhao2013
  • 2016-12-29 00:53
  • 1136

获取字节码文件的相关内容

反射机制是指在运行状态中,对任意一个类(class文件),都能知道这个类的所有属性和方法;对任意一个对象,都能调用这个对象的方法和属性。这种动态的获取信息和动态的调用对象的方法的功能称为——Java语言的反射机制。简单点说,动态的获取类中的信息,这就是Java的反射机制。在Java的反射机制中,我们...
  • qq_35246620
  • qq_35246620
  • 2016-12-12 16:36
  • 347

什么是字节码文件?

什么是字节码文件? 字节码文件是经过编译器预处理过的一种文件,是JAVA的执行文件存在形式。 它本身是二进制文件,但是不可以被系统直接执行,而是需要虚拟机(JVM)解释执行。由于被预处理过,所以比一般的解释代码要快,但是仍然会比系统直接执行的慢。
  • zh521zh
  • zh521zh
  • 2015-08-28 11:52
  • 841

java字节码文件详解

看过java虚拟机。。。 Java为什么能够支持跨平台,其实关键就是在于其*.class字节码文件,因为*.class字节码文件有一个统一标准的规范,里面是JVM运行的时需要的相关指令,各家的JVM必须能够解释编译执行标准字节码文件,因此Java是一种跨平台语言,再想想C++/C等语言为什么不是跨...
  • keep_moving_cqu
  • keep_moving_cqu
  • 2013-07-07 01:59
  • 6164
    个人资料
    • 访问:957424次
    • 积分:12879
    • 等级:
    • 排名:第1271名
    • 原创:258篇
    • 转载:85篇
    • 译文:11篇
    • 评论:954条
    博主的 GitHub 账号
    GitHub : Charies Gavin

        鉴于 CSDN 糟糕的用户体验,博主会将一些优质的文章迁移到 Charies Gavin's Blog  欢迎大家在 GitHub 上 Follow 博主,以及 Fork、Star、Watch 博主的项目。


      青春不老 奋斗不止


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