反射简介和反射测试

大家好,我是一个爱举铁的程序员Shr。

本篇文章介绍反射。

源码地址:https://github.com/ShrMus/Dao/tree/master/dao_20180603/src/main/java/com/shrmus/reflex

一、什么是反射?

能够分析类能力的程序成为反射[1]。

二、反射可以用来做什么?

 

在运行中分析类的能力。

在运行中查看对象,例如,编写一个toString方法供所有类使用。

实现通用的数组操作代码。

利用Method对象,这个对象很像C++中的函数指针。

 

三、反射中的重要元素

3.1 Class类

Class类能够保存每个类的信息。

Object类中的getClass()方法可以返回一个Class类的实例。

newInstance() 方法可以创建Class对象所表示的类的一个新实例。

3.2 Field类

Field类保存类中的字段的信息。

clazz.getFields()方法可以获取类中所有可访问的公共字段。

3.3 Constructor类

Constructor类保存类的构造方法的信息。

clazz.getDeclaredConstructor(Class<?>... parameterTypes)可以获取类的所有带参数或不带参数的构造方法。

3.4 Method类

Method类保存类的方法的信息。

clazz.getMethod(String name, Class<?>... parameterTypes)方法可以获得类的所有带参数或者不带参数的公共方法。

method.invoke(Object obj, Object... args)用来执行方法。第一个参数是底层调用该方法的对象,第二个可变参数就是方法的形参。

3.5 Modifier类

Modifier类提供了static方法和常量,对类和成员访问修饰符进行解码。

3.6 Type接口

Type接口保存的是类型信息,包括原始类型、参数化类型、数组类型、类型变量和基本类型。

四、反射实战操作

4.1 反射实例化新对象

4.1.1 新建一个类,只写字段

public class Student {
    private int id;
    private String name;
    protected int age;
    public int gender;
}

4.1.2 写一个测试类

public class StudentTest {
    /**
     * 反射实例化新对象
     */
    @Test
    public void newInstance() throws Exception{
        // 原对象
        Student student = new Student();
        System.out.println(student);
        // 原对象的Class对象
        Class<? extends Student> clazz = student.getClass();
        // 实例化一个新对象
        Student newInstance = clazz.newInstance();
        System.out.println(newInstance);
        // 获取类的全路径
        String name = clazz.getName();
        System.out.println(name);
    }
}

运行结果:

com.shrmus.reflex.Student@69d0a921

com.shrmus.reflex.Student@446cdf90

com.shrmus.reflex.Student

可以看到第一个对象的地址和第二个对象的地址不一样,所以证实了反射实例化的是一个新对象。

4.2 反射获取字段

4.2.1 测试获取字段

    /**
     * 反射获取字段
     */
    @Test
    public void getDeclaredFields() throws Exception {
        Class clazz = Student.class;
        // 根据字段名获取字段的信息
        Field field1 = clazz.getDeclaredField("name");
        System.out.println(field1.toGenericString());
        // 获取类中的所有字段
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            System.out.println(Modifier.toString(field.getModifiers()) + " " + field.getGenericType().getTypeName() + " " + clazz.getName() + "." + field.getName());
        }
    }

运行结果:

private java.lang.String com.shrmus.reflex.Student.name

private int com.shrmus.reflex.Student.id

private java.lang.String com.shrmus.reflex.Student.name

protected int com.shrmus.reflex.Student.age

public int com.shrmus.reflex.Student.gender

4.3 反射获取构造方法

4.3.1 添加构造方法

    public Student() {
    }
    public Student(int id) {
        this.id = id;
    }
    public Student(String name) {
        this.name = name;
    }
    private Student(int id,String name) {
        this.id = id;
        this.name = name;
    }
    protected Student(int id,String name,int age) {
        this.id = id;
        this.name = name;
        this.age = age;
    }
    public Student(int id,String name,int age,int gender) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

 

4.3.2 测试获取构造方法

    /**
     * 反射获取构造方法
     */
    @Test
    public void getDeclaredConstructors() throws Exception {
        Class clazz = Student.class;
        // 根据构造方法的参数个数获取构造方法
        Constructor constructor1 = clazz.getDeclaredConstructor(Integer.TYPE,String.class,Integer.TYPE);
        System.out.println(constructor1.toGenericString());
        // 获取所有构造方法
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for(Constructor constructor : constructors) {
            System.out.print(Modifier.toString(constructor.getModifiers()) + " " + constructor.getName());
            // 获取参数类型
            Type[] genericParameterTypes = constructor.getGenericParameterTypes();
            System.out.print("(");
            if(genericParameterTypes.length > 0) {
                int length = genericParameterTypes.length;
                for(int i = 0; i < length - 1; i++) {
                    String typeName = genericParameterTypes[i].getTypeName();
                    System.out.print(typeName + ", ");
                }
                System.out.print(genericParameterTypes[length - 1].getTypeName());
            }
            System.out.print(")");
            System.out.println();
        }
    }

运行结果:

protected com.shrmus.reflex.Student(int,java.lang.String,int)

public com.shrmus.reflex.Student(int, java.lang.String, int, int)

protected com.shrmus.reflex.Student(int, java.lang.String, int)

private com.shrmus.reflex.Student(int, java.lang.String)

public com.shrmus.reflex.Student()

public com.shrmus.reflex.Student(int)

public com.shrmus.reflex.Student(java.lang.String)

4.4 反射获取成员方法

4.4.1 添加成员方法

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getGender() {
        return gender;
    }
    public void setGender(int gender) {
        this.gender = gender;
    }
    private void test01() throws RuntimeException{
    }
    protected void test02() throws SQLException{
    }
    public static String test03() {
        return "test03()";
    }
    public static final Student test04(String string1,Student student) {
        System.out.println(string1 + " " + student.getName());
        return student;
    }

4.4.2 测试获取成员方法

    /**
     * 反射获取类的所有方法
     */
    @Test
    public void getDeclaredMethods() throws Exception {
        Class<? extends Student> clazz = Student.class;
        // 根据方法名获取方法对象
        Method declaredMethod = clazz.getDeclaredMethod("test04",String.class,Student.class);
        Student student = clazz.newInstance();
        // 执行方法
        String string = "haha";
        student.setName("张三");
        Object invoke = declaredMethod.invoke(student,string,student);
        System.out.println(invoke);
        // 获取所有方法,不包括构造方法
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for(Method method : declaredMethods) {
            System.out.print(Modifier.toString(method.getModifiers()) + " " + method.getGenericReturnType().getTypeName() + " " + clazz.getName() + "." + method.getName());
            // 获取参数类型
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            System.out.print("(");
            if(genericParameterTypes.length > 0) {
                int length = genericParameterTypes.length;
                for(int i = 0; i < length - 1; i++) {
                    String typeName = genericParameterTypes[i].getTypeName();
                    System.out.print(typeName + ", ");
                }
                System.out.print(genericParameterTypes[length - 1].getTypeName());
            }
            System.out.print(")");
            System.out.println();
        }
    }

运行结果:

haha 张三

com.shrmus.reflex.Student@446cdf90

public java.lang.String com.shrmus.reflex.Student.getName()

public int com.shrmus.reflex.Student.getId()

public void com.shrmus.reflex.Student.setName(java.lang.String)

public static final com.shrmus.reflex.Student com.shrmus.reflex.Student.test04(java.lang.String, com.shrmus.reflex.Student)

private void com.shrmus.reflex.Student.test01()

public static java.lang.String com.shrmus.reflex.Student.test03()

public int com.shrmus.reflex.Student.getAge()

public int com.shrmus.reflex.Student.getGender()

protected void com.shrmus.reflex.Student.test02()

public void com.shrmus.reflex.Student.setGender(int)

public void com.shrmus.reflex.Student.setId(int)

public void com.shrmus.reflex.Student.setAge(int)

参考文献

[1] (美)霍斯特曼(Horstmann),科内尔(Cornell).Java核心技术卷1:基础知识(原书第9版)[M].机械工业出版社,2013

源码地址:https://github.com/ShrMus/Dao/tree/master/dao_20180603/src/main/java/com/shrmus/reflex

猜你喜欢

转载自blog.csdn.net/ShrMuscles/article/details/80553863
今日推荐