本篇內容主要講解“JAVA編程中的反射用法總結”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“JAVA編程中的反射用法總結”吧!
下面對Java反射的基礎知識進行說明和總結:
總結
首先定義一個MyBase類,其中有私有字段,也有公有字段。同時也有公有方法和私有方法。MyBase類示例如下:
package com.hwdev.demo; /** * 基類示例 * @author wangming */ public class MyBase { //公有字段 public int version = 1; //私有字段 private String date = "2021-05-18" ; //公有方法 public void say2(String msg){ System.out.println("Hello " + msg); } //私有方法 private String getData(){ return this.date; } }//加入Java開發交流君樣:756584822一起吹水聊天
這里再定義一個Hello類,它繼承自MyBase類,通過繼承主要用于驗證一下反射對于父類、子類的反射用法。
package com.hwdev.demo; /** * * @author wangming */ public class Hello extends MyBase { public String author = "JackWang" ; public int version = 1; private String company = "kzcloud" ; public void say(String msg){ System.out.println("Hello " + msg); } public void setAuthor(String author){ this.author = author; } public String getAuthor(){ return this.author; } private int getVersion(){ return this.version; } }
關于Java反射,功能強大的就是可以通過字符串配置來動態從系統中調用方法或者修改其中某個對象的字段值,而Class.forName方法即可以通過傳入類全路徑字符串名稱來獲取對應的Class對象,非常的方便。另外通過getField方法和GetMethod方法可以獲取指定字段和方法,并動態調用。
package com.hwdev.demo; import java.lang.reflect.*; import java.util.Arrays; /** * 反射第一種用法 Class.forName * @author wangming */ public class ReflectDemo01 { public static void Test() { try { //通過字符串全路徑類名查找Class Class helloC = Class.forName("com.hwdev.demo.Hello"); //獲取所有公有的字段數組,私有的無法獲取 Field [] fields = helloC.getFields(); //打印字段數組內容//加入Java開發交流君樣:756584822一起吹水聊天 System.out.println(Arrays.toString(fields)); //[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version] //實例化 Object obj = helloC.newInstance(); //獲取特定字段,比遍歷Field[]效率更高 Field f = helloC.getField("author"); if (f != null){ //關閉安全檢查,提高效率 f.setAccessible(true); //獲取字段author內容 String author = (String)f.get(obj); System.out.println("author=" + author); //author=JackWang } //獲取所有公有的方法數組,私有的無法獲取 Method [] methods = helloC.getMethods(); //打印方法數組內容,子類等方法也可以獲取到 System.out.println(Arrays.toString(methods)); //本類所有方法 Method [] methods2 = helloC.getDeclaredMethods(); //打印方法數組內容 System.out.println(Arrays.toString(methods2)); //獲取特定方法,第二個參數String.class為say方法的參數類型 //say(java.lang.String) Method m = helloC.getDeclaredMethod("say",String.class); if (m != null){ //關閉安全檢查,提高效率 m.setAccessible(true); //獲取字段author內容 Object returnValue = m.invoke(obj, new Object[]{"Java"}); //Hello Java if (returnValue!=null){ System.out.println("returnValue =" + returnValue); } }//加入Java開發交流君樣:756584822一起吹水聊天 }catch(ClassNotFoundException | SecurityException ex){ ex.printStackTrace(); } catch(Exception ex){ ex.printStackTrace(); } } }
這里需要注意:xxx.getMethods()方法默認情況下,會返回本類、父類、父接口的公有方法,而xxx.getDeclaredMethods()返回本類的 所有方法,包括私有的方法。同理,反射API中其他getXXX和getDeclaredXXX的用法類似。
package com.hwdev; import com.hwdev.demo.ReflectDemo01; /** * * @author wangming */ public class Main { /** * @param args the command line arguments */ public static void main(String[] args) { //反射第一種用法 Class.forName ReflectDemo01.Test(); } }
執行程序,輸出的結果如下:
[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version, public int com.hwdev.demo.MyBase.version] author=JackWang [public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), public void com.hwdev.demo.MyBase.say2(java.lang.String), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()] [public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), private int com.hwdev.demo.Hello.getVersion()] Hello Java
從輸出結果上來看,Field [] fields = helloC.getFields();
不但可以獲取Hello類的公有字段,還可以獲取到父類MyBase的公有字段:com.hwdev.demo.MyBase.version
而Method [] methods2 = helloC.getDeclaredMethods();則可以獲取本類,即Hello類所有的方法,包括公有的方法和私有的方法。因此,Java反射可以訪問類的私有字段和方法,從而暴露內部的信息,這也是Java反射有安全問題的原因。
由于Java方法支持重載,因此同名的方法可以存在多個,即參數不同,因此在用反射調用方法時,需要指定方法的參數類型,這樣就可以明確調到的具體是哪個方法簽名,如`Method m = helloC.getDeclaredMethod("say",String.class); `調用的是`public void com.hwdev.demo.Hello.say(java.lang.String) `。
除了可以用Class.forName來進行反射外,還可以通過如下方式來獲取反射對象:
Hello hello = new Hello(); Class helloC = hello.getClass(); Field [] fields = helloC.getFields(); // Class helloC = Hello.class; Field [] fields = helloC.getFields();
下面介紹一下如何用Java反射修改私有字段和調用私有方法的示例:
package com.hwdev.demo; import java.lang.reflect.*; /** * 反射訪問私有字段和方法 * @author wangming */ public class ReflectDemo02 { //加入Java開發交流君樣:756584822一起吹水聊天 public static void Test() { try { //通過已有類查找Class Class helloC = Hello.class; //實例化 Object obj = helloC.newInstance(); //獲取特定私有字段 Field f = helloC.getDeclaredField("company"); if (f != null){ //私有必須開啟 f.setAccessible(true); //設置私有字段值 f.set(obj, "newKZ"); //獲取字段author內容 String fv = (String)f.get(obj); System.out.println("company=" + fv); //company=newKZ } //獲取私有方法 Method m = helloC.getDeclaredMethod("getVersion", null); if (m != null){ //私有必須開啟 m.setAccessible(true); Object returnValue = m.invoke(obj, null); if (returnValue!=null){ //returnValue =1 System.out.println("returnValue =" + returnValue); } } }catch(SecurityException ex){ ex.printStackTrace(); } catch(Exception ex){ ex.printStackTrace(); } } }
另外,Java反射可以獲取注解信息,這個對于ORM框架來講,用的非常多。
package com.hwdev.demo; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 注解示例 * @author wangming */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ORMAnnotation { public String FieldName(); public String FieldType(); }
其中,@Retention(RetentionPolicy.RUNTIME)表示注解可以在運行時通過反射訪問。@Target(ElementType.FIELD) 表示這個注解只能用在字段上面。同理,可以把FIELD改為Type或者Method等。
package com.hwdev.demo; import java.lang.annotation.Annotation; import java.lang.reflect.*; /** * 反射或者字段注解 * @author wangming *///加入Java開發交流君樣:756584822一起吹水聊天 public class ReflectDemo03 { public static void Test() { try { Class helloC = Class.forName("com.hwdev.demo.HelloAnnotation"); Field[] fields = helloC.getDeclaredFields(); for(Field f : fields){ //關閉安全檢查,提高效率 f.setAccessible(true); Annotation ann = f.getAnnotation(ORMAnnotation.class); if(ann instanceof ORMAnnotation){ ORMAnnotation ormAnn = (ORMAnnotation) ann; System.out.println("FieldName=" + ormAnn.FieldName()); System.out.println("FieldType=" + ormAnn.FieldType()); } } }catch(ClassNotFoundException | SecurityException ex){ ex.printStackTrace(); } catch(Exception ex){ ex.printStackTrace(); } } }
執行此示例,則輸出如下:
FieldName=f_author FieldType=varchar(50) FieldName=f_ver FieldType=int
再次,介紹一下如何用反射獲取方法參數個數和類型,其中包含泛型的信息獲?。?/p>
package com.hwdev.demo; import java.util.ArrayList; import java.util.List; /** * 泛型示例 * @author wangming */ public class GenericCls { protected List<String> myList = new ArrayList(); public GenericCls(int size){ for(int i = 0;i<size;i++){ myList.add("item"+i); } } public List<String> getList(){ return this.myList; } public String getList(int idx){ return this.myList.get(idx); } } package com.hwdev.demo; import java.lang.reflect.*; /** * 反射獲取方法參數 * @author wangming */ public class ReflectDemo05 { public static void Test() { try { //加入Java開發交流君樣:756584822一起吹水聊天 Class helloC = Class.forName("com.hwdev.demo.GenericCls"); //構造函數調用 Object obj = helloC.getConstructor(int.class).newInstance(3); Method method = helloC.getMethod("getList", int.class); Class<?> returnType = method.getReturnType(); System.out.println("ReturnType = " + returnType.getName()); Parameter[] params = method.getParameters(); for(Parameter p : params){ System.out.println("ParameterizedType = " + p.getParameterizedType()); System.out.println("getModifiers = " + p.getModifiers()); System.out.println("getName = " + p.getName()); System.out.println("getType = " + p.getType()); } //調用方法 Object ret = method.invoke(obj, new Object[]{2}); System.out.println("ret = " + ret.toString()); Method method2 = helloC.getMethod("getList", null); Type greturnType = method2.getGenericReturnType(); System.out.println("getGenericReturnType = " + returnType.getName()); if(greturnType instanceof ParameterizedType){ ParameterizedType type = (ParameterizedType) greturnType; System.out.println("type = " + type.getTypeName()); Type[] typeArguments = type.getActualTypeArguments(); for(Type typeArgument : typeArguments){ Class typeArgClass = (Class) typeArgument; System.out.println("typeArgClass = " + typeArgClass); } } }catch(ClassNotFoundException | SecurityException ex){ ex.printStackTrace(); } catch(Exception ex){ ex.printStackTrace(); } } }
執行此示例,則輸出如下:
R`eturnType = java.lang.String ParameterizedType = int getModifiers = 0 getName = arg0 getType = int ret = item2 getGenericReturnType = java.lang.String type = java.util.List<java.lang.String> typeArgClass = class java.lang.String
到此,相信大家對“JAVA編程中的反射用法總結”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。