<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
反射是Java程式語言中的一個特性。它允許執行的Java程式檢查或 操作 自身,並操作程式的內部屬性。例如,Java類可以獲取其所有成員的名稱並顯示它們。
從程式內部檢查和操作Java類的能力聽起來可能不太顯示,但是在其他程式語言中,這個特性根本不存在。例如,在C或C ++ 程式中無法獲取有關該程式中定義的函數的資訊。
反射的一個具體用途是在JavaBeans中,軟體元件可以通過一個構建工具進行視覺化操作。該工具使用反射來獲取Java元件 (類) 動態載入時的屬性。
要了解反射是如何工作的,請考慮以下簡單範例:
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName(args[0]); Method m[] = c.getDeclaredMethods(); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString()); } catch (Throwable e) { System.err.println(e); } } }
對於以下項的呼叫:
java DumpMethods java.util.Stack
輸出為:
public java.lang.Object java.util.Stack.push( java.lang.Object) public synchronized java.lang.Object java.util.Stack.pop() public synchronized java.lang.Object java.util.Stack.peek() public boolean java.util.Stack.empty() public synchronized int java.util.Stack.search(java.lang.Object)
也就是說,類的方法名稱java.util.Stack
列出了它們及其完全限定的引數和返回型別。
此程式使用載入指定的類 class.forName
, 然後呼叫 getDeclaredMethods
方法檢索類中定義的方法列表. java.lang.reflect.Method
是表示單個類方法的類。
反射類,例如Method
,在java.lang.反射中找到。使用這些類必須遵循三個步驟。第一步是獲得一個java.lang.Class
要操作的類的物件。java.lang.Class
用於表示正在執行的Java程式中的類和介面。
獲取類物件的一種方法是:
Class c = Class.forName("java.lang.String");
上述程式碼獲取的類物件 String
.
另一種方法是使用:
Class c = int.class;
或者
Class c = Integer.TYPE;
獲取基本型別的類資訊。後一種方法存取預定義TYPE
包裝型別 (例如Integer
) 為基本型別。
第二步是呼叫方法,例如getDeclaredMethods
,以獲取該類宣告的所有方法的列表。
一旦掌握了這些資訊,那麼第三步就是使用反射API來操作這些資訊。例如:
Class c = Class.forName("java.lang.String"); Method m[] = c.getDeclaredMethods(); System.out.println(m[0].toString());
在下面的範例中,將三個步驟結合在一起,以呈現如何使用反射處理特定應用的獨立插圖。
一旦掌握了類資訊,下一步通常是詢問有關類物件的基本問題。
例如,Class.isInstance
方法可以用來模擬instanceof
運算:
class A {} public class instance1 { public static void main(String args[]) { try { Class cls = Class.forName("A"); boolean b1 = cls.isInstance(new Integer(37)); System.out.println(b1); boolean b2 = cls.isInstance(new A()); System.out.println(b2); } catch (Throwable e) { System.err.println(e); } } }
在此範例中,類物件A
被建立,然後我們檢查類範例物件,以檢視它們是否是A
。Integer(37)
不是,但是new A()
是。
反射最有價值和最基本的用途之一是找出類中定義了哪些方法。為此,可以使用以下程式碼:
import java.lang.reflect.*; public class method1 { private int f1( Object p, int x) throws NullPointerException { if (p == null) throw new NullPointerException(); return x; } public static void main(String args[]) { try { Class cls = Class.forName("method1"); Method methlist[] = cls.getDeclaredMethods(); for (int i = 0; i < methlist.length; i++) { Method m = methlist[i]; System.out.println("name = " + m.getName()); System.out.println("decl class = " + m.getDeclaringClass()); Class pvec[] = m.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println(" param #" + j + " " + pvec[j]); Class evec[] = m.getExceptionTypes(); for (int j = 0; j < evec.length; j++) System.out.println("exc #" + j + " " + evec[j]); System.out.println("return type = " + m.getReturnType()); System.out.println("-----"); } } catch (Throwable e) { System.err.println(e); } } }
程式首先獲取method1的類描述,然後呼叫getDeclaredMethods
(一個用於獲取類中定義的每個方法的函數)檢索Method
物件列表。這些方法包括public、protect、package和priva。如果你在程式中使用getMethods
而不是getDeclaredMethods
,還可以獲取繼承方法的資訊。
程式的輸出為:
name = f1 decl class = class method1 param #0 class java.lang.Object param #1 int exc #0 class java.lang.NullPointerException return type = int ----- name = main decl class = class method1 param #0 class [Ljava.lang.String; return type = void -----
使用類似的方法來找出類別建構函式。例如:
import java.lang.reflect.*; public class constructor1 { public constructor1() { } protected constructor1(int i, double d) { } public static void main(String args[]) { try { Class cls = Class.forName("constructor1"); Constructor ctorlist[] = cls.getDeclaredConstructors(); for (int i = 0; i < ctorlist.length; i++) { Constructor ct = ctorlist[i]; System.out.println("name = " + ct.getName()); System.out.println("decl class = " + ct.getDeclaringClass()); Class pvec[] = ct.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Class evec[] = ct.getExceptionTypes(); for (int j = 0; j < evec.length; j++) System.out.println( "exc #" + j + " " + evec[j]); System.out.println("-----"); } } catch (Throwable e) { System.err.println(e); } } }
在此範例中沒有檢索到返回型別資訊,因為建構函式實際上沒有真正的返回型別。
執行此程式時,輸出為:
name = constructor1 decl class = class constructor1 ----- name = constructor1 decl class = class constructor1 param #0 int param #1 double -----
還可以找出類中定義了哪些資料欄位。為此,可以使用以下程式碼:
import java.lang.reflect.*; public class field1 { private double d; public static final int i = 37; String s = "testing"; public static void main(String args[]) { try { Class cls = Class.forName("field1"); Field fieldlist[] = cls.getDeclaredFields(); for (int i = 0; i < fieldlist.length; i++) { Field fld = fieldlist[i]; System.out.println("name = " + fld.getName()); System.out.println("decl class = " + fld.getDeclaringClass()); System.out.println("type = " + fld.getType()); int mod = fld.getModifiers(); System.out.println("modifiers = " + Modifier.toString(mod)); System.out.println("-----"); } } catch (Throwable e) { System.err.println(e); } } }
此範例與前面的範例相似。一個新功能是使用Modifier
。這是一個反射類,表示在欄位成員上找到的修飾符,例如private int
。修飾符本身由整數表示,並且Modifier.toString
用於返回預設宣告順序中的字串表示形式 (例如final
之前的static
)。程式的輸出為:
name = d decl class = class field1 type = double modifiers = private ----- name = i decl class = class field1 type = int modifiers = public static final ----- name = s decl class = class field1 type = class java.lang.String modifiers = -----
與方法一樣,可以僅獲取有關類中宣告的欄位的資訊 (getDeclaredFields
),或獲取有關超類中定義的欄位的資訊 (getFields
)。
到目前為止,已經提出的例子都與獲取class有關。但是也可以以其他方式使用反射,例如呼叫指定名稱的方法。
要了解其工作原理,請考慮以下範例:
import java.lang.reflect.*; public class method2 { public int add(int a, int b) { return a + b; } public static void main(String args[]) { try { Class cls = Class.forName("method2"); Class partypes[] = new Class[2]; partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Method meth = cls.getMethod( "add", partypes); method2 methobj = new method2(); Object arglist[] = new Object[2]; arglist[0] = new Integer(37); arglist[1] = new Integer(47); Object retobj = meth.invoke(methobj, arglist); Integer retval = (Integer)retobj; System.out.println(retval.intValue()); } catch (Throwable e) { System.err.println(e); } } }
假設一個程式想要呼叫add
方法,但直到執行時才知道。也就是說,在執行期間指定方法的名稱 (例如,這可以由JavaBeans開發環境完成)。上面的程式展示了一種方法。
getMethod
用於在類中查詢具有兩個integer引數型別並具有適當名稱的方法。一旦找到此方法並將其捕獲到Method
物件,它是在適當型別的物件範例上呼叫的。要呼叫方法,必須構造一個參數列,基本整數值為37和47Integer
物件。返回值 (84) 也被包含在Integer
物件。
建構函式不等同於方法呼叫,因為呼叫建構函式等同於建立新物件 (最準確地說,建立新物件涉及記憶體分配和物件構造)。所以最接近前面例子的是:
import java.lang.reflect.*; public class constructor2 { public constructor2() { } public constructor2(int a, int b) { System.out.println( "a = " + a + " b = " + b); } public static void main(String args[]) { try { Class cls = Class.forName("constructor2"); Class partypes[] = new Class[2]; partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Constructor ct = cls.getConstructor(partypes); Object arglist[] = new Object[2]; arglist[0] = new Integer(37); arglist[1] = new Integer(47); Object retobj = ct.newInstance(arglist); } catch (Throwable e) { System.err.println(e); } } }
它查詢處理指定引數型別並呼叫它的建構函式,以建立物件的新範例。這種方法的價值在於它純粹是動態的,在執行時而不是在編譯時使用建構函式查詢和呼叫。
反射的另一個用途是改變物件中資料欄位的值。它的值再次從反射的動態性質中匯出,其中可以在執行程式中按名稱查詢欄位,然後更改其值。以下範例說明了這一點:
import java.lang.reflect.*; public class field2 { public double d; public static void main(String args[]) { try { Class cls = Class.forName("field2"); Field fld = cls.getField("d"); field2 f2obj = new field2(); System.out.println("d = " + f2obj.d); fld.setDouble(f2obj, 12.34); System.out.println("d = " + f2obj.d); } catch (Throwable e) { System.err.println(e); } } }
在此範例中,d欄位的值設定為12.34。
反射的一個用途是建立和運算元組。Java語言中的陣列是類的一種特殊型別,並且可以將陣列參照分配給Object
。
要檢視陣列的工作方式,請考慮以下範例:
import java.lang.reflect.*; public class array1 { public static void main(String args[]) { try { Class cls = Class.forName( "java.lang.String"); Object arr = Array.newInstance(cls, 10); Array.set(arr, 5, "this is a test"); String s = (String)Array.get(arr, 5); System.out.println(s); } catch (Throwable e) { System.err.println(e); } } }
此範例建立一個10長的字串陣列,然後將陣列中的位置5設定為字串值。將檢索並顯示該值。
以下程式碼說明了對陣列的更復雜的操作:
import java.lang.reflect.*; public class array2 { public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; Object arr = Array.newInstance(Integer.TYPE, dims); Object arrobj = Array.get(arr, 3); Class cls = arrobj.getClass().getComponentType(); System.out.println(cls); arrobj = Array.get(arrobj, 5); Array.setInt(arrobj, 10, 37); int arrcast[][][] = (int[][][])arr; System.out.println(arrcast[3][5][10]); } }
此範例建立一個5x10x15的int陣列,然後繼續將陣列中的位置 [3][5][10] 設定為值37。請注意,多維陣列實際上是陣列陣列,因此,例如,在第一個array.get之後,arrobj中的結果是10x15陣列。再次將其剝離以獲得15長的陣列,並使用Array.setInt
。
請注意,建立的陣列型別是動態的,不必在編譯時知道。
Java反射非常有用,因為它支援按名稱動態檢索有關類和資料結構的資訊,並允許在執行的Java程式中進行操作。此功能非常強大,但是也要謹慎使用
以上就是Java中反射的學習筆記分享的詳細內容,更多關於Java反射的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45