java反射的应用场景和解析方法

 
 
什么是反射?

正常场景下,java从源码到运行有3个阶段:
source class runtime

反射提供的是runtime阶段获取类的class实例、方法、属性、注解,并且能够调用类的方法的途径,这种动态获取类信息和调用类方法的机制被称之为反射

为什么要使用反射?

正常的实例化一个对象

ClassA objA = new ClassA();
objA.sayHello();

通过反射去实例化一个对象

ClassA objA  = (ClassA)ClassA.class.newInstance();
Method method = objA.getMethod("sayHello");
method.invoke();

在source阶段实际上二者并无任何区别,反射也没有体现出任何的优势,那么任何一个java开发人员必然会问为什么要使用反射?
反射的重点在于runtime阶段的获取类信息和调用类方法,那么当你的编码过程中中有“部分信息是source阶段不清晰,需要在runtime阶段动态临时加载”这种场景,反射就可以派上用场了

我们考虑几个编码场景:
1、编码阶段不知道需要实例化的类名是哪个,需要在runtime从配置文件中加载:

Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();

2、在runtime阶段,需要临时访问类的某个私有属性

ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);

所以,反射的优点在于“有些编码需求在source阶段无法实现,只能在runtime阶段通过反射实现”,而非“source阶段正常编码方式能解决的,反射的方式能解决的更好”,所以比较反射和正常编码方式的优劣是没有意义的,反射解决的是正常编码无法解决的编码场景,如果正常编码方式可以解决的,强行使用反射反而是毫无意义的,编码不是为了show技巧。

反射应用范例代码

实现对类或者对象的构造器、方法、属性、注解的获取和操作,具体作用见代码中的注释描述

public class ReflectionHelper {

    /**
     * Reflection Test Code
     *
     * @param args
     */
    public static void main(String[] args) {
        SSHClient sshClient = new SSHClient();

        // 获取class名称
        System.out.println("01-----获取class名称-----");
        System.out.println(sshClient.getClass().getName());
        System.out.println(sshClient.getClass().getSimpleName());
        System.out.println(sshClient.getClass().getTypeName());

        Class<?> clazz1 = null;
        Class<?> clazz2 = null;
        Class<?> clazz3 = null;

        // 获取对象或者类的Class实例
        try {
            clazz1 = Class.forName(sshClient.getClass().getName());
            clazz2 = sshClient.getClass();
            clazz3 = ReflectionUtils.class;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        // 获取类的构造函数,用构造函数实例一个对象
        for (Constructor<?> clazz1Cstor : clazz1.getConstructors()) {
            System.out.println(clazz1Cstor.getName());
            try {
                SSHClient client1 = (SSHClient) clazz1.newInstance();
                SSHClient client2 = (SSHClient) clazz1Cstor.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }

        }

        // 获取类定义的方法、属性
        System.out.println("02-----获取类定义的方法、属性-----");
        try {
            SSHClient client = (SSHClient) clazz1.newInstance();
            Method setHostMethod = clazz1.getDeclaredMethod("setHost", String.class);
            setHostMethod.invoke(client, "111");

            Field field = client.getClass().getDeclaredField("host");
            field.setAccessible(true);
            System.out.println(field.get(client));
            field.set(client,"a new host");
            System.out.println(field.get(client));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 获取类的注解
        System.out.println("03-----获取类使用的注解-----");
        for (Annotation annotation : clazz1.getAnnotations()) {
            System.out.println(annotation.getClass().getName());
            System.out.println(annotation.toString());
            System.out.println(annotation.annotationType());
        }
    }
}

运行结果:




作者:测试你个头
链接:http://www.jianshu.com/p/9d13a9eeccdf
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/tectrol/article/details/78848066