Java反射

類中類html

1.  反射介紹java

       反射這一律念最先由編程開發人員Smith在1982年提出,主要指應用程序訪問、檢測、修改自身狀態與行爲的能力。這一律唸的提出馬上吸引了編程界的極大關注,各類研究工做隨之展開,隨之而來引起編程革命,出現了多種支持反射機制的面嚮對象語言。web

在計算機科學領域,反射是指一類可以自我描述和自控制的應用。在Java編程語言中,反射是一種強有力的工具,是面向抽象編程一種實現方式,它能使代碼語句更加靈活,極大提升代碼的運行時裝配能力。編程

2. 反射在java中的體現api

Java反射說的是在運行狀態中,對於任何一個類,咱們都可以知道這個類有哪些方法和屬性。對於任何一個對象,咱們都可以對它的方法和屬性進行調用。咱們把這種動態獲取對象信息和調用對象方法的功能稱之爲反射機制。案例:mybatis


https://programmer.help/blogs/reflection-and-dynamic-agent-in-mybatis.htmloracle

 

2.1  獲取Class對象

反射實際上是獲取類的字節碼文件(在JVM的世界裏只會有有一份,無論以不一樣的方式加載多少次),也就是.class文件,那麼咱們就能夠經過Class這個對象進行獲取,有三種方式:經過類名的class屬性、對象的getClass()方法和java.lang.Class的靜態方法forName(「類全路徑」)

import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; /** * * @author dgm * @describe "java 反射測試" * @date 2020年5月11日 */ public class ReflectionClassTest { public static void main(String[] args) { //獲取Class對象(三種方式) Class<?> ChildClassFirst = ChildClass.class; Class<?> ChildClassSecond = new ChildClass(1).getClass(); Class<?> ChildClassThird = null; try { // below method is used most of the times in frameworks like JUnit //Spring dependency injection, Tomcat web container //Eclipse auto completion of method names, hibernate, Struts2 etc. //because ChildClass is not available at compile time ChildClassThird = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("first: "+ ChildClassFirst.getCanonicalName()); System.out.println("second: "+ ChildClassSecond.getCanonicalName()); System.out.println("third: "+ ChildClassThird.getCanonicalName()); System.out.println(ChildClassFirst==ChildClassSecond); System.out.println(ChildClassFirst==ChildClassThird); System.out.println(ChildClassSecond==ChildClassThird); } } 

 輸出效果:app


 

2.2  獲取類全部的公共public構造器

可用getConstructors()返回類的全部公共構造器

import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; /** * * @author dgm * @describe "java 公共構造器測試" * @date 2020年5月11日 */ public class ReflectionConstructorTest { public static void main(String[] args) { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; // 獲取全部公共構造器 Constructor<?>[] publicConstructors = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 已經肯定能Class對象,實際狀況須要作判斷類加載是否成功 publicConstructors = ChildClass.getConstructors(); System.out.println("公共構造器個數:" + publicConstructors.length); for (Constructor constructor : publicConstructors) { System.out.println("構造器:" + constructor); } } } 
輸出效果:


源文件的構造器:框架


2.3  獲取類全部的公共public field屬性編程語言

可用getFields()返回類的全部公共屬性(包括從父類和接口繼承過來的)

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; /** * * @author dgm * @describe "java 公共field屬性測試" * @date 2020年5月11日 */ public class ReflectionFieldTest { public static void main(String[] args) { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; // 獲取全部公共field屬性(包括從父類和接口繼承過來的) Field[] publicFields = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 已經肯定有Class對象,實際狀況須要作判斷類加載是否成功 publicFields = ChildClass.getFields(); System.out.println("公共field個數:" + publicFields .length); for (Field field : publicFields ) { System.out.println("field屬性:" + field); } } } 

輸出效果:


 

2.4  獲取類全部的公共public方法

可用getMethods()返回類的全部公共方法(包括從父類和接口繼承過來的)

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; /** * * @author dgm * @describe "java 公共方法測試" * @date 2020年5月11日 */ public class ReflectionMethodTest { public static void main(String[] args) { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; // 獲取全部公共public方法(包括從父類和接口繼承過來的) Method[] publicMethods = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 已經肯定有Class對象,實際狀況須要作判斷類加載是否成功 publicMethods = ChildClass.getMethods(); System.out.println("公共方法個數:" + publicMethods .length); for (Method method : publicMethods ) { System.out.println("公共方法:" + method); } } } 

輸出:


 

2.5  獲取類全部的註解

可用getAnnotations()返回類的全部註解

@Deprecated public class ChildClass extends BaseClass implements BaseInterface { 。。。。。。 }

測試代碼:

/** * * @author dgm * @describe "java 註解測試" * @date 2020年5月11日 */ public class ReflectionAnnotationTest { public static void main(String[] args) { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; // 獲取全部註解 Annotation[] annotations = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 已經肯定有Class對象,實際狀況須要作判斷類加載是否成功 annotations = ChildClass.getAnnotations(); System.out.println("註解個數:" + annotations .length); for (Annotation annotation : annotations ) { System.out.println("註解:" + annotation); } } } 

輸出效果:


 

3.  如何使用經過反射獲得構造器、field屬性、方法、註解

3.1  使用構造器

既能夠一次性獲取全部構造器,不過也能夠單獨參數化獲取構造器

public class ReflectionConstructorUseTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; // 獲取全部公共構造器 Constructor<?>[] publicConstructors = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 已經肯定有Class對象,實際狀況須要作判斷類加載是否成功 publicConstructors = ChildClass.getConstructors(); System.out.println("公共構造器個數:" + publicConstructors.length); for (Constructor constructor : publicConstructors) { System.out.println("構造器:" + constructor); /*Class[] ParameterTypes = constructor.getParameterTypes(); if(ParameterTypes.length>0) { Object myObj = constructor.newInstance(10); }*/ } //獲取構造器(沒有獲取全部構造器,「參數化」獲取構造器),測試我是獲取第一個構造器 //框架裏喜歡這樣寫代碼,但碼農式開發是不須要這樣寫的 Constructor<?> constructor = ChildClass.getConstructor(int.class); System.out.println(Arrays.toString(constructor.getParameterTypes())); //用獲取到的構造器實例化對象 Object object = constructor.newInstance(99); //經過「參數化」獲取類裏的方法 Method method = ChildClass.getMethod("method1", null); //執行方法 method.invoke(object, null); //獲取其餘方法(看需求了) method = ChildClass.getMethod("method2", String.class); method.invoke(object, "dongguagming"); } } 

輸出效果:


3.2  使用方法

既能夠一次性獲取全部方法,不過也能夠單獨參數化獲取方法

3.2.1 獲取公有方法(參數化和非參數化)

/** * * @author dgm * @describe "java 方法使用測試" * @date 2020年5月11日 */ public class ReflectionMethodUseTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } //獲取構造器(沒有獲取全部構造器,「參數化」獲取構造器),測試我是獲取第一個構造器 Constructor<?> constructor = ChildClass.getConstructor(int.class); System.out.println(Arrays.toString(constructor.getParameterTypes())); //用獲取到的構造器實例化對象 Object object = constructor.newInstance(99); //經過「參數化」獲取類裏的公用方法 Method method = ChildClass.getMethod("method1", null); //執行方法 method.invoke(object, null); //獲取其餘共有方法(看需求了) method = ChildClass.getMethod("method2", String.class); method.invoke(object, ",方法 dongguagming"); } }

3.2.2  獲取私有方法(無參和有參數化)

/** * * @author dgm * @describe "java 方法使用測試" * @date 2020年5月11日 */ public class ReflectionMethodUseTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> ChildClass = null; try { ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } //獲取構造器(沒有獲取全部構造器,「參數化」獲取構造器),測試我是獲取第一個構造器 Constructor<?> constructor = ChildClass.getConstructor(int.class); System.out.println(Arrays.toString(constructor.getParameterTypes())); //用獲取到的構造器實例化對象 Object object = constructor.newInstance(99); //經過「參數化」獲取類裏的公用方法 Method method = ChildClass.getMethod("method1", null); //執行方法 method.invoke(object, null); //獲取其餘共有方法(看需求了) method = ChildClass.getMethod("method2", String.class); method.invoke(object, ",方法 dongguagming"); //獲取private私有方法 Class<?> baseClass = Class.forName("code.reflection.BaseClass"); method = baseClass.getDeclaredMethod("method3", null); method.setAccessible(true); //執行私有方法 method.invoke(object, null); method = baseClass.getDeclaredMethod("method3", String.class); method.setAccessible(true); //執行私有方法 method.invoke(object, ",確實是私有方法有參"); } } 

 最終輸出:


3.3 使用field屬性

3.3.1  參數化獲取某個具體的field屬性

import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; /** * * @author dgm * @describe "java Field使用測試" * @date 2020年5月11日 */ public class ReflectionFieldUseTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> baseClass = null; Class<?> ChildClass = null; try { baseClass = Class.forName("code.reflection.BaseClass"); ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Field field = ChildClass.getField("interfaceInt"); System.out.println("field屬性:"+field); } } 

輸出:


3.3.2  獲取field屬性的從屬類或接口

import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; /** * * @author dgm * @describe "java Field使用測試" * @date 2020年5月11日 */ public class ReflectionFieldUseTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException { // 獲取Class對象(用的是java.lang.Class.forName()) Class<?> baseClass = null; Class<?> ChildClass = null; try { baseClass = Class.forName("code.reflection.BaseClass"); ChildClass = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Field field = ChildClass.getField("interfaceInt"); //System.out.println("field屬性:"+field); Class<?> fieldClass = field.getDeclaringClass(); System.out.println("field屬性在:"+fieldClass.getCanonicalName()+"中定義"); } } 

輸出:

 

3.3.3  獲取field屬性的類

只寫了核心代碼「:

Field field = ChildClass.getField("interfaceInt"); Class<?> fieldType = field.getType(); System.out.println("field屬性的類型是:"+fieldType.getCanonicalName()); 

 

 

3.3.4  設置和獲取公用public field屬性的值

只寫了核心代碼「:

field = ChildClass.getField("publicInt"); //獲取構造器(沒有獲取全部構造器,「參數化」獲取構造器),測試我是獲取第一個構造器 Constructor<?> constructor = ChildClass.getConstructor(int.class); //用獲取到的構造器實例化對象 Object object = constructor.newInstance(99); System.out.println("field屬性的值是:"+field.get(object)); //設置field屬性的值 field.setInt(object, 100); System.out.println("field屬性的值是:"+field.get(object)); 

輸出:


 

3.3.5  設置和獲取私有private field屬性的值

只寫了核心代碼「:

//獲取私有private field Field privateField = ChildClass.getDeclaredField("privateString"); privateField.setAccessible(true); System.out.println("私有field屬性的默認值是:"+privateField.get(object)); //設置私有field屬性的值 privateField.set(object, "哪怕你是私有,我也要更改你的值"); System.out.println("私有field屬性的更改以後的值是:"+privateField.get(object)); 

輸出:

 

3.4 使用註解

不細分了,要否則又寫不完了

定義註解

@Documented @Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) @Inherited @Retention(RetentionPolicy.RUNTIME) public @interface CustomAnnotation { public String name(); public String value(); }

具體類中使用,只寫核心代碼:

@CustomAnnotation(name="ChildClass level", value = "ChildClass Class Annotation") @CustomAnnotation(name="public field level", value = "public field Annotation") public int publicInt; @Override @CustomAnnotation(name="method1 level", value = "Method1 Annotation ") public void method1() { System.out.println("我是無參公共public方法 Method1 impl."); } @Override @CustomAnnotation(name="method2 level", value = "Method2 Annotation ") public int method2(String str) { System.out.println("我是有參公共public方法 Method2 impl." +str); return 0; }

測試代碼:

import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.Arrays; /** * * @author dgm * @describe "java 註解測試" * @date 2020年5月11日 */ public class ReflectionAnnotationUseTest { public static void main(String[] args) { //獲取Class對象(三種方式) Class<?> ChildClassFirst = ChildClass.class; Class<?> ChildClassSecond = new ChildClass(1).getClass(); Class<?> ChildClassThird = null; try { // below method is used most of the times in frameworks like JUnit //Spring dependency injection, Tomcat web container //Eclipse auto completion of method names, hibernate, Struts2 etc. //because ChildClass is not available at compile time ChildClassThird = Class.forName("code.reflection.ChildClass"); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(ChildClassFirst==ChildClassSecond); System.out.println(ChildClassFirst==ChildClassThird); System.out.println(ChildClassSecond==ChildClassThird); // 獲取類的全部註解 Annotation[] classAnnotation = ChildClassFirst.getAnnotations(); System.out.println(ChildClassFirst.getName()+"有"+classAnnotation.length+"個註解"); for (Annotation ca : classAnnotation) { if (ca instanceof CustomAnnotation) { CustomAnnotation customAnnotation = (CustomAnnotation) ca; System.out.println("class name: " + customAnnotation.name()); System.out.println("class value: " + customAnnotation.value()); } } // 獲取類的公有field Field[] fields = ChildClassFirst.getFields(); for (Field field : fields) { field.setAccessible(true); Annotation[] fieldAnnotation = field.getAnnotations(); for (Annotation fa : fieldAnnotation) { System.out.println(field.getName()+"有"+fieldAnnotation.length+"個註解"); if (fa instanceof CustomAnnotation) { CustomAnnotation customAnnotation = (CustomAnnotation) fa; System.out .println("field name: " + customAnnotation.name()); System.out.println("field value: " + customAnnotation.value()); } } } // 獲取類的公有方法 Method[] methods = ChildClassFirst.getMethods(); for (Method method : methods) { method.setAccessible(true); Annotation[] methodAnnotation = method.getAnnotations(); for (Annotation ma : methodAnnotation) { System.out.println(method.getName()+"有"+methodAnnotation.length+"個註解"); if (ma instanceof CustomAnnotation) { CustomAnnotation customAnnotation = (CustomAnnotation) ma; System.out.println("method name: " + customAnnotation.name()); System.out.println("method value: " + customAnnotation.value()); } } } } } 

 

出結果:

 

總結:  構造器、方法、註解,一句話反射很重要!!!

 

參考:

0 java反射 : https://baike.baidu.com/item/JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/6015990?fr=aladdin

1. Interface AnnotatedElement

https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/AnnotatedElement.html

2.   Reflection and Dynamic Agent in Mybatis 

https://programmer.help/blogs/reflection-and-dynamic-agent-in-mybatis.html

相關文章
相關標籤/搜索