---
# System prepended metadata

title: Reflection
tags: [Java]

---

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