# Reflection 反射可以讓在執行的Java程式獲取自身的資訊, 可以用來動態操作程式內部屬性。 像是可以取一個class的fields/methods,繼承的class..., 進行基本操作 如: create object, access fields, invoke methods... 但是, 反射運行很慢, 不是正常會用到的作法, 能不用就不要用。 底下取一些常用的方法的範例: ## Class 假設我們有一個class Player: ```java= public class Player { public static String aStaticField = "hello"; public static String aStaticMethod() { return "ayo"; } public String name; public Player() { this("default"); } public Player(String name) { this.name = name; } public void setName(String name){ this.name = name; } public String getName(){ return name; } } ``` ### 取得"Player"這個類別的Class物件 Class.forName(classPath); ```java= Class<?> clazz = Class.forName("Player"); ``` 用Class直接.class ```java= Class<Player> clazz = Player.class; ``` 用Instance直接getClass() ```java= Player player = new Player(); Class<Player> clazz = player.getClass(); ``` ## new Instance 使用Class#newInstance()方法 先看一下原本的寫法: ```java= Player p = new Player(); Player p2 = new Player("andy"); ``` Reflection寫法: ```java= Object p = clazz.newInstance(); ``` 如果要執行有Parameter的Constructor: ```java= Constructor<?> constructor = clazz.getConstructor(String.class); Object p2 = constructor.newInstance("andy"); ``` ## Class Members 基本上就是直接用``get...()``方法, 回傳一個Field/Method陣列 但是, 方法有兩種: 一種是``get...()`` 這個方法會回傳 "自己+所有父類別裡面" 的public members 另一種是``getDeclared...()`` 這個方法會回傳 "自己" 的所有members <br> 為了方便, 底下範例全部用getDeclared...()方法 ## Field: ### 取得所有Fields: ```java= Field[] f = clazz.getDeclaredFields(); ``` ### 取得單一Field: ```java= Field f = clazz.getDeclaredField("name"); ``` ### 取得field的值 Field#get(instance) #### non-static field: ```java= Player p = new Player("warren"); Field f = p.getClass().getDeclaredField("name"); Object fieldValue = f.get(p); System.out.println(fieldValue); // "warren" ``` #### static field: static instance直接給null就好了 ```java= Field f = clazz.getDeclaredField("aStaticField"); Object fieldValue = f.get(null); System.out.println(fieldValue); //"hello" ``` ### 設定field的值 Field#set(instance,value) #### non-static field: ```java= Player p = new Player(); Field f = clazz.getDeclaredField("name"); f.set(p,"kevin"); Object fieldValue = f.get(p); System.out.println(fieldValue); // "kevin" System.out.println(p.getName()); // "kevin" ``` #### static field: ```java= Field f = clazz.getDeclaredField("aStaticField"); f.set(null,"good"); Object fieldValue = f.get(null); System.out.println(fieldValue); //"good" System.out.println(Player.aStaticField); //"good" ``` ## Method ### 取得所有Methods: ```java= Method[] f = clazz.getDeclaredMethods(); ``` ### 取得單一Method: 無參數: ```java= Method f = clazz.getDeclaredMethod("getName"); ``` 有參數: ```java= Method f = clazz.getDeclaredMethod("setName",String.class); ``` ### 執行Method Method#invoke(instance,parameter...) #### non-static Method ```java= Player p = new Player("andy"); Method f = clazz.getDeclaredMethod("setName",String.class); Object returnValue = f.invoke(p,"鮭魚"); System.out.println(returnValue); // null System.out.println(p.getName()); // "鮭魚" ``` #### static Method ```java= Method f = clazz.getDeclaredMethod("aStaticMethod"); Object returnValue = f.invoke(null); System.out.println(returnValue); // "ayo" ``` :::info :bulb: **除了這些操作外, 還有很多方法可以用, 詳見** https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html :::