java反射机制
java反射机制
很喜欢这句话——“当我们面对一项新的知识时,我们往往需要知道三方面,它是什么,它能做什么,它比原有知识强在哪里,我们该怎么使用它。当你能够解决这些问题时,便意味着你已经对这项知识入门了。”
一、定义(是什么)
Java反射机制是在运行状态中,对任意一个类,都能够知道这个类的属性和方法,对任意一个对象,都能够调用这个对象的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。
一般而言,开发者社群说到动态语言,大致认同的一个定义是:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl、Python、Ruby是动态语言,C++、Java、C#不是动态语言。
尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是“反射、映象、倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种“看透class”的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)
二、功能
1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3)在运行时判断任意一个类所属的成员变量和方法
4)在运行时调用类的任意方法
5)生成动态代理
三、为什么用
一般情况下,我们使用一个事先知道的类或方法,如通过new方法获取对应对象。当某些类经常变化,或者不确定,或者编译期未知时,可以通过反射,在运行时获取该类的属性、方法,或者调用某些方法。
四、Class(Java反射的起源)
Class类是Java反射的起源,如果没有Class,就不能调用反射相关的api。
在Java应用中,Class类的实例代表了classes和interfaces,也包括enum, annotation, array, 8种原生数据类型(byte, short, int, long, float, double, char, boolean)以及 void。Class类的构造器是私有的,意味着Class对象只能由JVM自动生成,每当class字节码被JVM加载或者defineClass()方法被调用时,Class对象就会由JVM自动生成。
public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement { /* * Private constructor. Only the Java Virtual Machine creates Class objects. * This constructor is not used and prevents the default constructor being * generated. */ private Class(ClassLoader loader) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. classLoader = loader; } ... ... }
五、获取Class对象的途径
package com.ttx.java.reflect; /** * 使用java中的反射 * @author TimFruit * @date 18-9-23 下午9:06 */ public class TestReflect { //http://www.importnew.com/23902.html public static void main(String[] args) throws ClassNotFoundException { ClassPathway pathway=new ClassPathway(); System.out.println(pathway.getClassByClass()); //==> class com.ttx.java.reflect.ClassPathway System.out.println(pathway.getClassByGetClassMethod()); //==> class com.ttx.java.reflect.ClassPathway System.out.println(pathway.getClassByGetSupperClassMethod()); //==> class java.lang.Object System.out.println(pathway.getClassByForNameMethod()); //==> class com.ttx.java.reflect.ClassPathway } } /** * 获取class对象的途径 */ class ClassPathway{ Class getClassByClass(){ return ClassPathway.class; } Class getClassByGetClassMethod(){//常用,由对象获取对应的类 ClassPathway pathway=new ClassPathway(); return pathway.getClass(); } Class getClassByGetSupperClassMethod(){ ClassPathway pathway=new ClassPathway(); Class pathwayClazz=pathway.getClass(); return pathwayClazz.getSuperclass(); } Class getClassByForNameMethod() throws ClassNotFoundException {//常用,通过静态方法以及对应的类名获取 return Class.forName("com.ttx.java.reflect.ClassPathway"); } }
六、反射可使用的api (怎样用)
package com.ttx.java.reflect; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 使用反射中的api * @author TimFruit * @date 18-10-5 上午12:13 */ public class ClassAPITests { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { //反射的主要作用是运行时观察类的属性、方法,并且调用方法 People tim=new People("tim"); Class clazz=tim.getClass(); //1.获取构造器 并构造实例 constructInstance(clazz); // ==> 张三 - com.ttx.java.reflect.People@4f47d241 //2.获取方法 并调用方法 invokeMethod(clazz,"work",tim); // ==> tim正在工作... //3.识别标注的注解,调用对应的方法 invokeMethod(clazz,InvokeMethod.class,tim); // ==> tim正在工作... //4.设置属性 setProperty(clazz,tim,"name","ttx-new-name"); System.out.println(tim.getName()); // ==> ttx-new-name //5. methodsAndDeclaredMethodsDifferences(clazz); /* ==> getMethods()... 个数:12 work | toString | getName | setName | wait | wait | wait | equals | hashCode | getClass | notify | notifyAll | getDeclaredMethods()... 个数:5 work | testMethod | toString | getName | setName | */ } public static void constructInstance(Class targetClazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //1.获取构造器 并构造实例 Constructor constructor=targetClazz.getConstructor(String.class); Object obj=constructor.newInstance("张三");//新建实例 System.out.println(obj); } public static void invokeMethod(Class targetClazz,String methodName,Object invokeObj) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //2.获取方法 并调用方法 Method workMethod=targetClazz.getMethod(methodName); workMethod.invoke(invokeObj); //第一个参数为调用的对象 类似tim.work() } public static void invokeMethod(Class targetClazz, Class annotationClazz,Object invokeObj) throws InvocationTargetException, IllegalAccessException { //3.识别标注的注解,调用对应的方法 Method[] methods=targetClazz.getMethods(); for(Method method : methods){ Annotation annotation=method.getAnnotation(annotationClazz); if(annotation!=null){ method.invoke(invokeObj); } } } public static void setProperty(Class targetClazz, Object targetObj, String propertyName, Object value) throws NoSuchFieldException, IllegalAccessException { Field field=targetClazz.getDeclaredField(propertyName); //获取属性 field.setAccessible(true); //设置私有(private)属性可以直接访问 field.set(targetObj,value); } public static void methodsAndDeclaredMethodsDifferences(Class targetClazz){ Method[] methods=targetClazz.getMethods(); //用于获取类所有public的方法,包括继承的方法 System.out.println("\r\ngetMethods()..."); System.out.println("个数:"+methods.length); for(Method method: methods){ System.out.print(method.getName() +" | "); } Method[] declaredMethods=targetClazz.getDeclaredMethods(); //用于获取自身类声明的方法,包括public, protected, private的方法 System.out.println("\r\ngetDeclaredMethods()..."); System.out.println("个数:"+declaredMethods.length); for(Method method: declaredMethods){ System.out.print(method.getName() +" | "); } } }
public class People { private String name; public People() { } public People(String name) { this.name=name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @InvokeMethod public void work(){ System.out.println(name+"正在工作..."); } @Override public String toString() { return name+" - "+super.toString(); } private void testMethod(){ System.out.println("用于测试getMethods和getDeclaredMethods的区别"); } }
/** * 用于反射识别方法 * @author TimFruit * @date 18-10-5 上午12:48 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface InvokeMethod { }
学习资料: