Java編程思想(十八) —— 再談反射__演算法

來源:互聯網
上載者:User

在Java編程思想(十五) —— 類型資訊之反射和Java編程思想(十六) —— 聯絡JVM再談Class,書上只用了3頁就講完了,還有講了那麼多Class的東西,接下來要從反射中怎麼用,自己結合API和其他資料再寫多一些。


樣本:Test.java

public class Test {        public Test() {        }        public Test(int i) {          System.out.println(i);        } private void pri() {System.out.println("private");}public void pub() {System.out.println("public");}protected void pro() {System.out.println("protected");}private String pristr;public String pubstr;protected String pro;}

有不同的方法和域。


測試:

import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class Reflect {public static void main(String[] args) {try {//測試參數類型後面跟著三點的作用Test t = new Test();t.three();t.three("a","b","c");//輸出[] [a,b,c] 證明...表示的參數可以為空白或者是傳字元數組  即可傳可不傳  英文成為varargs//將Test裝載進命名空間   得到代表Test的Class對象引用Class c = Class.forName("Test");//Method類  拿到名為pub的方法try {Method one = c.getMethod("pub");try {//方法調用 invoke(Object obj, Object... args)  obj為所要調用方法所屬的類  args為方法所傳的參數//所傳obj要為執行個體 ,不然會有object is not an instance of declaring classone.invoke(c.newInstance());} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}} catch (NoSuchMethodException e1) {e1.printStackTrace();} catch (SecurityException e1) {e1.printStackTrace();}//這種返回的方法的數組   為公用方法 包括那些父類和父介面中繼承的方法Method[] method = c.getMethods();//返回的是該Class對象代表的類聲明的所有方法  這樣就包括public private protected方法 Method[] declaredmethod = c.getDeclaredMethods();Class[] array = c.getClasses();Field[] field = c.getFields();Field[] declaredfield = c.getDeclaredFields();for (int i = 0; i < array.length; i++) {System.out.println("Classes array is "+array[i].getName());}for (int i = 0; i < method.length; i++) {System.out.println("Methods array is "+method[i].getName());}//getReturnType拿到方法返回的屬性。for (int i = 0; i < declaredmethod.length; i++) {System.out.println("DeclaredMethods array is "+declaredmethod[i].getReturnType().getName()+" "+declaredmethod[i].getName());try {try {String s[] ={"1","2"}; //如果沒有設定 就會有Class Reflect can not access a member of class Test with //modifiers "private"異常//Constructor, Field, Method 為AccessibleObject的子類//有著存取控制的許可權  預設是false  會強制java進行 訪問檢查  所以private是禁止訪問的  Filed同理declaredmethod[i].setAccessible(true);System.out.println(declaredmethod[i].getName());if(declaredmethod[i].getName().equals("three")){System.out.println("true");//下面這條會報 wrong number of arguments異常 //這個問題是搞了我最久的東西  中文都是前篇一律的胡說八道//invoke(Object obj, Object... args)   數組是協變的 String[]被當成Object[]//String[] 被當成了整個參數 而string數組裡面的元素又不是object //而不是args的第一個參數,其實,我們String數組是Objec數組的第一個元素/*這是因為編譯器會把字串數組當作一個可變長度參數傳給對象o,而我們取得方法只有一個參數,所以就會出現wrong number ofarguments的異常,我們只要把字串數組強制轉換為一個Object對象就可以解決這個異常了  這個簡直就是放屁*///declaredmethod[i].invoke(c.newInstance(),s);declaredmethod[i].invoke(c.newInstance(),new Object[]{s});declaredmethod[i].invoke(c.newInstance(),(Object)new String[]{"1","2","3"});declaredmethod[i].invoke(c.newInstance(),(Object)null);declaredmethod[i].invoke(c.newInstance(),(Object)new String[]{});}else{declaredmethod[i].invoke(c.newInstance());}} catch (InstantiationException e) {e.printStackTrace();}} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}}//與Method同理,只不過Filed拿到的是域。for (int i = 0; i < field.length; i++) {System.out.println("Fields array is "+field[i].getName());}for (int i = 0; i < declaredfield.length; i++) {System.out.println("Declaredfieds array is "+declaredfield[i].getName());try {declaredfield[i].setAccessible(true);declaredfield[i].set(t, "a");} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}System.out.println(t.pro);System.out.println(t.pub);} catch (ClassNotFoundException e) {e.printStackTrace();}}}

基本所有的問題和屬性方法都在裡面,不過wrong number of arguments異常,是我查了最久的異常,靜下心來後看懂了。

這是因為編譯器會把字串數組當作一個可變長度參數傳給對象o,而我們取得方法只有一個參數,
所以就會出現wrong number of arguments的異常,我們只要把字串數組強制轉換為一個Object對象就可以解決這個異常了。


全部都是這個錯誤的答案,invoke(Object obj, Object... args)  ,數組是協變的 String[]被當成Object[]。

String[] 被當成了整個參數 ,而string數組裡面的元素又不是object 。
而不是args的第一個參數,其實,我們String數組是Objec數組的第一個元素。


慢慢看就理解了。


後面補充:

Constructor<?>[] ct = Class.forName("Test").getConstructors();for (int i = 0; i < ct.length; i++) {System.out.println("Constructor:" + ct[i].getName());}System.out.println("new instance");try {ct[0].newInstance();ct[1].newInstance(123);} catch (InstantiationException | IllegalAccessException| IllegalArgumentException | InvocationTargetException e2) {e2.printStackTrace();}

Constructor就是構造器,不過不同於Class的newInstace方法,Constructor的newInstance(Object... initargs) 為varargs,即上面提到的三點。可以進行參數的傳入。

而有趣的一點是,Constructor數組是有序的,前提是你的構造方法寫在類裡面最前面,如果前面有其他方法,那麼數組的順序就不是按照排序而排了。


反射的作用,就是運行時檢查對象的類型,任意調用對象的方法(Spring和servlet中都用到了,注意到沒有,我們在xml配置,然後屬性會根據xml注入),同時可以知道方法參數和屬性。


雖然這算是打破了所謂的封裝性,private屬性,不過想想,沒有後門,語言豈不是死了。

對於反射,想瞭解跟多的可以看看國外的反射教程,http://www.programcreek.com/2013/09/java-reflection-tutorial/

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.