本文最后更新于:3 个月前
【参考】
Java 反射机制详解 - JavaGuide(√)
1 - 零碎点
反射是框架的灵魂,反射能够在运行时分析类、并且执行类中的方法。
反射能够获取任意一个类的所有的方法和属性,并且还能够调用这些方法和属性。
2 - 反射的应用场景
2.1 - 概述
框架、动态代理、注解。这三个内容会用到反射。
2.2 - 展开
==框架==
通过反射,能够大量的使用各种框架。像 Spring/Spring Boot、MyBatis 等等框架中都大量使用了反射机制。
==动态代理==
各种框架中也大量使用了动态代理,动态代理的实现也依赖反射。
比如在动态代理的实现过程中,会使用反射类Method
来调用指定的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class DebugInvocationHandler implements InvocationHandler {
private final Object target;
public DebugInvocationHandler(Object target) { this.target = target; }
public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException { System.out.println("before method " + method.getName()); Object result = method.invoke(target, args); System.out.println("after method " + method.getName()); return result; } }
|
==注解==
Java中的注解也用到了反射。
比如使用Spring的时候,@Component注解能够将一个类声明为Spring Bean,@Value注解能够读取到配置文件中的值。
这些都是通过反射分析类,来获取类/属性/方法/方法的参数上的注解,然后根据注解做进一步的分析。
3 - 反射机制的优缺点
3.1 - 优点
能够让代码更灵活,比如用于框架、动态代理来扩展切面功能、注解来方便开发
3.2 - 缺点
(1)==安全问题:==运行的时候能够分析并操作类,会增加安全问题,比如运行时使用反射创建对象会无视泛型的安全检查。
(2)==性能问题:==相对来说,发射的性能会比正射要差一些。
4 - 反射实战
4.1 - 获取 Class 对象的四种方式
获取一个类的方法、变量等信息需要从 Class 对象获取,因此要想动态的获取这些信息则需要获取Class对象。
Java 提供了四种获取一个类的 Class 对象的方式。
(1)通过类名获取:TargetObject.class
1
| Class alunbarClass = TargetObject.class;
|
通过此方式获取 Class 对象不会进行初始化
(2)通过类的完整名称(路径)获取:Class.forName(“cn.javaguide.TargetObject”)
1
| Class alunbarClass1 = Class.forName("cn.javaguide.TargetObject");
|
(3)通过类的对象获取:o.getClass()
1 2
| TargetObject o = new TargetObject(); Class alunbarClass2 = o.getClass();
|
(4)通过类加载器获取:xxxClassLoader.loadClass()传入类路径
1
| ClassLoader.getSystemClassLoader().loadClass("cn.javaguide.TargetObject");
|
通过类加载器获取 Class 对象不会进行初始化,意味着不进行包括初始化等一系列步骤,静态代码块和静态对象不会得到执行
4.2 - 反射的一些基本操作
(1)创建要使用反射操作的类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class TargetObject { private String value;
public TargetObject() { this.value = "alec"; }
public void publicMethod(String s) { System.out.println("I am " + s); }
public void privateMethod() { System.out.println("value is " + value); } }
|
(2)使用反射操作这个类的方法和参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class Main { public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException { Class<?> targetClass = Class.forName("TargetObject"); TargetObject targetObject = (TargetObject)targetClass.newInstance();
Method[] methods = targetClass.getDeclaredMethods(); for (Method e : methods) { System.out.println(e.getName()); }
Method publicMethod = targetClass.getDeclaredMethod("publicMethod", String.class); publicMethod.invoke(targetObject, "alec");
Method privateMethod = targetClass.getDeclaredMethod("privateMethod"); privateMethod.setAccessible(true); privateMethod.invoke(targetObject);
Field field = targetClass.getDeclaredField("value"); field.setAccessible(true); field.set(targetObject, "alec_changed"); privateMethod.invoke(targetObject); } }
publicMethod privateMethod I am alec value is alec value is alec_changed
|
5 - 反射类的常用方法总结
5.1 - Class.getDeclaredFields() 和 Class.getMethods() 的区别
参考:https://www.cnblogs.com/wy697495/p/9631909.html
==区别:==
两个方法的区别主要在于:getMethods()返回的是该类以及超类的公共方法。getDeclaredMethods()返回该类本身自己声明的包括公共、保护、默认(包)访问和私有方法,但并不包括超类中的方法。
总结:其实Class中有很多相似的方法比如:getAnnotations()和getDeclaredAnnotations(),以及getFields()和getDeclaredFields()等等,不同之处和上面基本一样
==例子:==
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public class TargetClass { public TargetClass() { }
public void publicMethod_1(){
}
protected void protectedMethod_2(){
}
void defaultMethod_3(){
}
private void privateMethod_4(){
} }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class TargetObject { private String value;
public TargetObject() { this.value = "alec"; }
public void publicMethod(String s) { System.out.println("I am " + s); }
public void privateMethod() { System.out.println("value is " + value); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| =============getMethods================== publicMethod_1 wait wait wait equals toString hashCode getClass notify notifyAll ===========getDeclaredMethods============= protectedMethod_2 privateMethod_4 defaultMethod_3 publicMethod_1 ==========================================
|
5.2 - 通过反射调用类的各种元素
1 2 3 4 5 6
| Classes,内部类; Field,属性; Constructor,构造器; Method,方法; Annotation,注解;
|