深刻淺析Java反射機制。本站提示廣大學習愛好者:(深刻淺析Java反射機制)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻淺析Java反射機制正文
Java反射機制是在運轉狀況中,關於隨意率性一個類,都可以或許曉得這個類的一切屬性和辦法;關於隨意率性一個對象,都可以或許挪用它的隨意率性一個辦法和屬性;這類靜態獲得的信息和靜態挪用對象的辦法的功效稱為Java說話的反射機制。反射的概念是由Smith在1982年初次提出的,重要是指法式可以拜訪、檢測和修正它自己狀況或行動的一種才能。這一概念的提出很快激發了盤算機迷信范疇關於運用反射性的研討。它起首被法式說話的設計范疇所采取,並在Lisp和面向對象方面獲得了成就。固然反射自己其實不是一個新概念,它能夠會使我們聯想到光學中的反射概念,雖然盤算機迷信付與了反射概念新的寄義,然則,從景象下去說,它們確切有某些相通的地方,這些有助於我們的懂得。
Java反射機制重要供給上面幾種用處:
在運轉時斷定隨意率性一個對象所屬的類
在運轉時結構隨意率性一個類的對象
在運轉時斷定隨意率性一個類所具有的成員變量和辦法
在運轉時挪用隨意率性一個對象的辦法
起首看一個簡略的例子,經由過程這個例子來懂得Java的反射機制是若何任務的。
package com.wanggc.reflection; import java.lang.reflect.Method; /** * Java 反射演習。 * * @author Wanggc */ public class ForNameTest { /** * 進口函數。 * * @param args * 參數 * @throws Exception * 毛病信息 */ public static void main(String[] args) throws Exception { // 取得Class Class<?> cls = Class.forName(args[0]); // 經由過程Class取得所對應對象的辦法 Method[] methods = cls.getMethods(); // 輸入每一個辦法名 for (Method method : methods) { System.out.println(method); } } }
當傳入的參數是java.lang.String時,會輸入以下成果
public boolean java.lang.String.equals(java.lang.Object) public java.lang.String java.lang.String.toString() public int java.lang.String.hashCode() public int java.lang.String.compareTo(java.lang.String) public int java.lang.String.compareTo(java.lang.Object) public int java.lang.String.indexOf(int) public int java.lang.String.indexOf(int,int) public int java.lang.String.indexOf(java.lang.String) public int java.lang.String.indexOf(java.lang.String,int) public static java.lang.String java.lang.String.valueOf(int) public static java.lang.String java.lang.String.valueOf(char) public static java.lang.String java.lang.String.valueOf(boolean) public static java.lang.String java.lang.String.valueOf(float) public static java.lang.String java.lang.String.valueOf(char[],int,int) public static java.lang.String java.lang.String.valueOf(double) public static java.lang.String java.lang.String.valueOf(char[]) public static java.lang.String java.lang.String.valueOf(java.lang.Object) public static java.lang.String java.lang.String.valueOf(long) public char java.lang.String.charAt(int) public int java.lang.String.codePointAt(int) public int java.lang.String.codePointBefore(int) public int java.lang.String.codePointCount(int,int) public int java.lang.String.compareToIgnoreCase(java.lang.String) public java.lang.String java.lang.String.concat(java.lang.String) public boolean java.lang.String.contains(java.lang.CharSequence) public boolean java.lang.String.contentEquals(java.lang.CharSequence) public boolean java.lang.String.contentEquals(java.lang.StringBuffer) public static java.lang.String java.lang.String.copyValueOf(char[]) public static java.lang.String java.lang.String.copyValueOf(char[],int,int) public boolean java.lang.String.endsWith(java.lang.String) public boolean java.lang.String.equalsIgnoreCase(java.lang.String) public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]) public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]) public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException public void java.lang.String.getBytes(int,int,byte[],int) public byte[] java.lang.String.getBytes() public byte[] java.lang.String.getBytes(java.nio.charset.Charset) public void java.lang.String.getChars(int,int,char[],int) public native java.lang.String java.lang.String.intern() public boolean java.lang.String.isEmpty() public int java.lang.String.lastIndexOf(java.lang.String) public int java.lang.String.lastIndexOf(int,int) public int java.lang.String.lastIndexOf(int) public int java.lang.String.lastIndexOf(java.lang.String,int) public int java.lang.String.length() public boolean java.lang.String.matches(java.lang.String) public int java.lang.String.offsetByCodePoints(int,int) public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int) public boolean java.lang.String.regionMatches(int,java.lang.String,int,int) public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence) public java.lang.String java.lang.String.replace(char,char) public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String) public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String) public java.lang.String[] java.lang.String.split(java.lang.String) public java.lang.String[] java.lang.String.split(java.lang.String,int) public boolean java.lang.String.startsWith(java.lang.String) public boolean java.lang.String.startsWith(java.lang.String,int) public java.lang.CharSequence java.lang.String.subSequence(int,int) public java.lang.String java.lang.String.substring(int) public java.lang.String java.lang.String.substring(int,int) public char[] java.lang.String.toCharArray() public java.lang.String java.lang.String.toLowerCase() public java.lang.String java.lang.String.toLowerCase(java.util.Locale) public java.lang.String java.lang.String.toUpperCase() public java.lang.String java.lang.String.toUpperCase(java.util.Locale) public java.lang.String java.lang.String.trim() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException 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 java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll()
如許就列出了java.lang.String類的一切辦法名、及其限制符、前往類型及拋出的異常。這個法式應用Class類forName辦法載入指定的類,然後挪用getMethods辦法前往指定類的辦法列表。java.lang.reflect.Method用來表述某個類中的單一辦法。
應用java的反射機制,普通須要遵守三步:
取得你想操作類的Class對象
經由過程第一步取得的Class對象去獲得操作類的辦法或是屬性名
操作第二步獲得的辦法或是屬性
Java運轉的時刻,某個類不管生成若干個對象,他們都邑對應統一個Class對象,它表現正在運轉法式中的類和接口。若何獲得操作類的Class對象,經常使用的有三種方法:
挪用Class的靜態辦法forName,如上例;
應用類的.class語法,如:Class<?> cls = String.class;
挪用對象的getClass辦法,如:String str = "abc";Class<?> cls = str .getClass();
上面將經由過程實例講述若何經由過程後面所訴的三步來履行某對象的某個辦法:
package com.wanggc.reflection; import java.lang.reflect.Method; /** * Java 反射演習。 * * @author Wanggc */ public class ReflectionTest { public static void main(String[] args) throws Exception { DisPlay disPlay = new DisPlay(); // 取得Class Class<?> cls = disPlay.getClass(); // 經由過程Class取得DisPlay類的show辦法 Method method = cls.getMethod("show", String.class); // 挪用show辦法 method.invoke(disPlay, "Wanggc"); } } class DisPlay { public void show(String name) { System.out.println("Hello :" + name); } }
後面說過,Java法式的每一個類都邑有個Class對象與之對應。Java反射的第一步就是取得這個Class對象,如代碼14行。固然,每一個類的辦法也必有一個Method對象與之對應。要經由過程反射的方法挪用這個辦法,就要起首取得這個辦法的Method對象,如代碼16行,然後用Method對象反過去挪用這個辦法,如代碼18行。留意16行getMethod辦法的第一個參數是辦法名,第二個是此辦法的參數類型,假如是多個參數,接著添加參數便可以了,由於getMethod是可變參數辦法。履行18行代碼的invoke辦法,其實也就是履行show辦法,留意invoke的第一個參數,是DisPlay類的一個對象,也就是挪用DisPlay類哪一個對象的show辦法,第二個參數是給show辦法傳遞的參數。類型和個數必定要與16行的getMethod辦法一向。
上例講述了若何經由過程反射挪用某個類的辦法,上面將再經由過程一個實例講述若何經由過程反射給某個類的屬性賦值:
package com.wanggc.reflection; import java.lang.reflect.Field; /** * Java 反射之屬性演習。 * * @author Wanggc */ public class ReflectionTest { public static void main(String[] args) throws Exception { // 樹立先生對象 Student student = new Student(); // 為先生對象賦值 student.setStuName("Wanggc"); student.setStuAge(); // 樹立拷貝目的對象 Student destStudent = new Student(); // 拷貝先生對象 copyBean(student, destStudent); // 輸入拷貝成果 System.out.println(destStudent.getStuName() + ":" + destStudent.getStuAge()); } /** * 拷貝先生對象信息。 * * @param from * 拷貝源對象 * @param dest * 拷貝目的對象 * @throws Exception * 破例 */ private static void copyBean(Object from, Object dest) throws Exception { // 獲得拷貝源對象的Class對象 Class<?> fromClass = from.getClass(); // 獲得拷貝源對象的屬性列表 Field[] fromFields = fromClass.getDeclaredFields(); // 獲得拷貝目的對象的Class對象 Class<?> destClass = dest.getClass(); Field destField = null; for (Field fromField : fromFields) { // 獲得拷貝源對象的屬性名字 String name = fromField.getName(); // 獲得拷貝目的對象的雷同稱號的屬性 destField = destClass.getDeclaredField(name); // 設置屬性的可拜訪性 fromField.setAccessible(true); destField.setAccessible(true); // 將拷貝源對象的屬性的值賦給拷貝目的對象響應的屬性 destField.set(dest, fromField.get(from)); } } } /** * 先生類。 */ class Student { /** 姓名 */ private String stuName; /** 年紀 */ private int stuAge; /** * 獲得先生姓名。 * * @return 先生姓名 */ public String getStuName() { return stuName; } /** * 設置先生姓名 * * @param stuName * 先生姓名 */ public void setStuName(String stuName) { this.stuName = stuName; } /** * 獲得先生年紀 * * @return 先生年紀 */ public int getStuAge() { return stuAge; } /** * 設置先生年紀 * * @param stuAge * 先生年紀 */ public void setStuAge(int stuAge) { this.stuAge = stuAge; } }
Java的發射機制中類有Class對應,類的辦法有Method對應,固然屬性也有Field與之對應。代碼中正文曾經做了具體的正文,在此不再贅述。但要留意,Field供給了get和set辦法獲得和設置屬性的值,然則因為屬性是公有類型,所以須要設置屬性的可拜訪性為true,如代碼50~51行。也能夠在為全部fields設置可拜訪性,在40行上面應用AccessibleObject的靜態辦法setAccessible,如:AccessibleObject.setAccessible(fromFields, true);
後面講述了若何用Java反射機制操作一個類的辦法和屬性,上面再經由過程一個實例講述若何在運轉時創立類的一個對象:
package com.wanggc.reflection; import java.lang.reflect.Field; /** * Java 反射之屬性演習。 * * @author Wanggc */ public class ReflectionTest { public static void main(String[] args) throws Exception { // 樹立先生對象 Student student = new Student(); // 為先生對象賦值 student.setStuName("Wanggc"); student.setStuAge(); // 樹立拷貝目的對象 Student destStudent = (Student) copyBean(student); // 輸入拷貝成果 System.out.println(destStudent.getStuName() + ":" + destStudent.getStuAge()); } /** * 拷貝先生對象信息。 * * @param from * 拷貝源對象 * @param dest * 拷貝目的對象 * @throws Exception * 破例 */ private static Object copyBean(Object from) throws Exception { // 獲得拷貝源對象的Class對象 Class<?> fromClass = from.getClass(); // 獲得拷貝源對象的屬性列表 Field[] fromFields = fromClass.getDeclaredFields(); // 獲得拷貝目的對象的Class對象 Object ints = fromClass.newInstance(); for (Field fromField : fromFields) { // 設置屬性的可拜訪性 fromField.setAccessible(true); // 將拷貝源對象的屬性的值賦給拷貝目的對象響應的屬性 fromField.set(ints, fromField.get(from)); } return ints; } } /** * 先生類。 */ class Student { /** 姓名 */ private String stuName; /** 年紀 */ private int stuAge; /** * 獲得先生姓名。 * * @return 先生姓名 */ public String getStuName() { return stuName; } /** * 設置先生姓名 * * @param stuName * 先生姓名 */ public void setStuName(String stuName) { this.stuName = stuName; } /** * 獲得先生年紀 * * @return 先生年紀 */ public int getStuAge() { return stuAge; } /** * 設置先生年紀 * * @param stuAge * 先生年紀 */ public void setStuAge(int stuAge) { this.stuAge = stuAge; } }
此例和上例運轉的成果是雷同的。然則copyBean辦法前往的對象不再是裡面傳入的,而是由辦法外部發生的,如第40行代碼所示。留意:Class的newInstance辦法,只能創立只包括無參數的結構函數的類,假如某類只要帶參數的結構函數,那末就要應用別的一種方法:fromClass.getDeclaredConstructor(int.class,String.class).newInstance(24,"wanggc");
至此,Java反射機制的經常使用性能(運轉時挪用對象的辦法、類屬性的應用、創類類的對象)曾經引見完了。
彌補:在取得類的辦法、屬性、結構函數時,會有getXXX和getgetDeclaredXXX兩種對應的辦法。之間的差別在於前者前往的是拜訪權限為public的辦法和屬性,包含父類中的;但後者前往的是一切拜訪權限的辦法和屬性,不包含父類的。
以上內容就是給年夜家引見的java發射機制,願望年夜家愛好。