Java程序员从笨鸟到菜鸟(四十八) 反射

原文转载自https://blog.csdn.net/sinat_38259539/article/details/71799078 对反射有非常全面的概述,非常感谢作者

反射是框架设计的灵魂

(使用的前提:必须先得到代表的字节码的 Class,Class 类用于表示 .class 文件(字节码))

一、反射的概述

Java 的反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象,而解剖使用的就是类中的方法,所以要先获取到每一个字节码文件对应的 class 类型的对象

反射就是把 java 类中的各种成分映射一个个的 java 对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对类进行解剖,把各个组成部分映射成一个个对象

二、查看 Class 类在 java 中的 api 详解

Class 类的实例表示正在运行的 Java 应用程序中的类和接口,每个类都有 Class 对象(包括基本数据类型)
Class 类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,不需要自己去处理创建,JVM 已经创建好了

三、反射的使用(这里使用 Student 类做演示)

1、获取 Class 对象的三种方式
1.1、Object–>getClass();
1.2、任何数据类型(包括基本数据类型)都有一个“静态”的 class 属性
1.3、通过 Class 类的静态方法:forName(String className)

package fanshe;

/**
 * create by tan on 2018/7/26
 * 获取 Class 对象的三种方式
 * 1.Object--> getClass();
 * 2.任何数据类型(包括基本数据类型)都有一个静态的 “class”属性
 * 3.通过 Class 类的静态方法:forName(类路径)
 **/
public class FanShe {
    public static void main(String[] args) {
        // 第一种方式获取 Class 对象
        Student student = new Student();
        // 获取 Class 对象
        Class stuClass = student.getClass();
        System.out.println(stuClass.getName());

        // 第二种方式获取 Class 对象
        Class stuClass2 = Student.class;
        // 判断两次获取的 Class 是否一致
        System.out.println(stuClass == stuClass2);

        // 第三种方式获取 Class 对象
        try {
            // 带包名的类路径
            Class stuClass3 = Class.forName("fanshe.Student");
            // 判断三种方式是否获取同一个 Class
            System.out.println(stuClass3 == stuClass2);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

运行结果:

fanshe.Student
true
true

Process finished with exit code 0

注意:在运行期间,一个类,只有一个 Class 对象产生

2、通过反射获取构造方法
Student 类:

package fanshe;

/**
 * create by tan on 2018/7/26
 * Student 类,包含构造方法
 **/
public class Student {
    //--------------- 构造方法 --------------------
    // 默认构造方法
    Student(String str) {
        System.out.println("默认构造方法 str = " + str);
    }

    // 无参构造方法
    public Student() {
        System.out.println("公有、无参构造方法执行了...");
    }

    // 有一个参数的构造方法
    public Student(char name) {
        System.out.println("姓名:" + name);
    }

    // 有多个参数的构造方法
    public Student(String name, int age) {
        System.out.println("姓名:" + name + " 年龄:" + age);
    }

    // 受保护的构造方法
    protected Student(boolean n) {
        System.out.println("受保护的构造方法 n = " + n);
    }

    // 私有构造方法
    private Student(int age) {
        System.out.println("私有构造方法 年龄:" + age);
    }
}

Constructors 类

package fanshe;

import java.lang.reflect.Constructor;

/**
 * create by tan on 2018/7/26
 * 通过 Class 对象可以获取某个类中的:构造方法、成员变量、成员方法;并访问成员
 * 1.获取构造方法:
 *  1.1 批量的方法:
 *          public Constructors[] getConstructors(); 获取所有公有的构造方法
 *          public Constructors[] getDeclaredConstructors(); 获取所有的构造方法
 *  1.2 获取单个的方法,并调用
 *          public Constructors getConstructor(Class... parameterTypes) 获取单个公有的构造方法
 *          public Constructors getDeclaredConstructor(class... parameterTypes); 获取某个构造方法
 *
 *          调用构造方法:
 *          Constructors-->newInstance(Object... initargs)
 **/
public class Constructors {
    public static void main(String[] args) throws Exception {
        // 1.加载 Class 对象
        Class clazz = Class.forName("fanshe.Student");

        // 2.获取所有公有构造方法
        System.out.println("*************** 所有公有构造方法 *****************");
        Constructor[] constructors = clazz.getConstructors();
        for (Constructor c: constructors) {
            System.out.println(c);
        }

        System.out.println("***************** 所有的构造方法 ******************");
       constructors = clazz.getDeclaredConstructors();
        for (Constructor c: constructors) {
            System.out.println(c);
        }

        System.out.println("*************** 获取公有、无参的构造方法 *********");
        Constructor con = clazz.getConstructor(null);
        System.out.println("con = " + con);

        // 调用构造方法
        Object obj = con.newInstance();

        System.out.println("************ 获取某个构造方法,并调用 *************");
        con = clazz.getDeclaredConstructor(char.class);
        System.out.println(con);

        // 调用构造方法
        con.setAccessible(true);
        obj = con.newInstance('男');
    }
}

运行结果:

*************** 所有公有构造方法 *****************
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
***************** 所有的构造方法 ******************
private fanshe.Student(int)
protected fanshe.Student(boolean)
public fanshe.Student(java.lang.String,int)
public fanshe.Student(char)
public fanshe.Student()
fanshe.Student(java.lang.String)
*************** 获取公有、无参的构造方法 *********
con = public fanshe.Student()
公有、无参构造方法执行了...
************ 获取某个构造方法,并调用 *************
public fanshe.Student(char)
姓名:男

Process finished with exit code 0

3、获取成员变量并调用
Student 类:

package fanshe.field;

/**
 * create by tan on 2018/7/26
 * Student 类
 **/
public class Student {
    // 姓名
    public String name;
    // 年龄
    protected int age;
    // 性别
    char sex;
    // 电话
    private String tel;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", tel='" + tel + '\'' +
                '}';
    }
}

Fields 类:

package fanshe.field;

import javafx.stage.FileChooser;

import java.lang.reflect.Field;

/**
 * create by tan on 2018/7/26
 * 获取成员变量,并调用
 * 1.批量的
 *      1.Field[] getFields(); 获取所有的公有字段
 *      2.Field[] getDeclaredFields(); 获取所有字段
 * 2.获取单个的
 *      1.public Field getField(String fieldName); 获取某个公有字段
 *      2.public Field getDeclaredField(String fieldName); 获取某个字段
 *
 *      设置字段的值:
 *          Field --> public void set(Object obj,Object value):
 **/
public class Fields {
    public static void main(String[] args) throws Exception {
        // 1.获取 Class 对象
        Class stuClass = Class.forName("fanshe.field.Student");

        // 2.获取字段
        System.out.println("************* 获取所有的公有字段 ****************");
        Field[] fields = stuClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("*************** 获取所有字段 *****************");
        fields = stuClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("**************** 获取所有的字段,并调用 *******************");
        Field field = stuClass.getField("name");
        System.out.println(field);

        // 获取一个对象
        Object obj = stuClass.getConstructor().newInstance();
        // 为字段设置值
        field.set(obj, "张三");
        // 验证
        Student stu = (Student)obj;
        System.out.println("验证姓名:" + stu.name);

        System.out.println("*********** 获取私有字段,并调用 ***************");
        field = stuClass.getDeclaredField("tel");
        System.out.println(field);
        field.setAccessible(true);
        field.set(obj, "123456");
        System.out.println("验证电话:" + stu);
    }
}

运行结果:

************* 获取所有的公有字段 ****************
public java.lang.String fanshe.field.Student.name
*************** 获取所有字段 *****************
public java.lang.String fanshe.field.Student.name
protected int fanshe.field.Student.age
char fanshe.field.Student.sex
private java.lang.String fanshe.field.Student.tel
**************** 获取所有的字段,并调用 *******************
public java.lang.String fanshe.field.Student.name
验证姓名:张三
*********** 获取私有字段,并调用 ***************
private java.lang.String fanshe.field.Student.tel
验证电话:Student{name='张三', age=0, sex= , tel='123456'}

Process finished with exit code 0

4、获取成员方法并调用
Student 类

package fanshe.method;

/**
 * create by tan on 2018/7/26
 * Student 类
 **/
public class Student {
    // ************ 成员方法 *****************
    public void show1(String str) {
        System.out.println("调用了:公有的,String 参数的 show1(): str = " + str);
    }
    protected void show2() {
        System.out.println("调用了:受保护的,无参数的 show2()");
    }
    void show3() {
        System.out.println("调用了:默认的,无参的 show3()");
    }
    private String show4(int age) {
        System.out.println("调用了:私有的,并且有返回值的,int 参数的 show4(): age = " + age);
        return "abcd";
    }
}

MethodClass 类

package fanshe.method;

import java.lang.reflect.Method;

/**
 * create by tan on 2018/7/26
 * 获取成员方法并调用
 * 1.批量的
 *      public Method[] getMethods(); 获取所有的公有方法
 *      public Method[] getDeclaredMethods(); 获取所有的成员方法
 * 2.获取单个的
 *      public Method getMethod(String name,Class<?>... parameterTypes)
 *      public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
 **/
public class MethodClass {
    public static void main(String[] args) throws Exception {
        // 1.获取 Class 对象
        Class stuClass = Class.forName("fanshe.method.Student");
        // 2.获取所有的公有方法
        System.out.println("********* 获取所有的公有方法 *********");
        stuClass.getMethods();
        Method[] methods = stuClass.getMethods();
        for (Method m: methods) {
            System.out.println(m);
        }

        // 3.获取所有的方法
        System.out.println("******** 获取所有的方法 ***************");
        methods = stuClass.getDeclaredMethods();
        for (Method m: methods) {
            System.out.println(m);
        }

        // 4.获取公有的 show1() 方法
        System.out.println("********** 获取公有的 show1 方法 *********");
        Method m = stuClass.getMethod("show1", String.class);
        System.out.println(m);
        // 实例化一个 Student 对象
        Object obj = stuClass.getConstructor().newInstance();
        m.invoke(obj, "张三");

        // 5.获取私有的 show4() 方法
        System.out.println("********* 获取私有的 show4() 方法 *********");
        m = stuClass.getDeclaredMethod("show4", int.class);
        System.out.println(m);
        m.setAccessible(true);
        Object result = m.invoke(obj, 20);
        System.out.println("返回值:" + result);
    }

}

运行结果:

********* 获取所有的公有方法 *********
public void fanshe.method.Student.show1(java.lang.String)
public final native java.lang.Class java.lang.Object.getClass()
public native int java.lang.Object.hashCode()
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
******** 获取所有的方法 ***************
public void fanshe.method.Student.show1(java.lang.String)
private java.lang.String fanshe.method.Student.show4(int)
protected void fanshe.method.Student.show2()
void fanshe.method.Student.show3()
********** 获取公有的 show1 方法 *********
public void fanshe.method.Student.show1(java.lang.String)
调用了:公有的,String 参数的 show1(): str = 张三
********* 获取私有的 show4() 方法 *********
private java.lang.String fanshe.method.Student.show4(int)
调用了:私有的,并且有返回值的,int 参数的 show4(): age = 20
返回值:abcd

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/u013090299/article/details/81181184