# 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
:::