リフレクションの基本の使い方について

servletをjunitでテストするにあたってprotectedにアクセスする必要が出た。
調べたらリフレクションを使えばアクセスができるっぽい。
備忘録として記載。

# 【目標】 Q.リフレクションとは？？

:参考記事達:
・リフレクションについて
https://qiita.com/suke_masa/items/0df3bb92bcb69f4a95d1
↑個人的にすごくわかりやすかった。

・ジェネリクスの\<?>について
https://qiita.com/pebblip/items/1206f866980f2ff91e77
↑たまにでてくる\<?>について

・junitでリフレクションのやり方
https://qiita.com/11295/items/b632850389831041b987
https://www.sejuku.net/blog/33252#:~:text=%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82-,private%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB%E3%83%89%E3%81%AE%E5%8F%82%E7%85%A7%E3%81%A8%E5%A4%89%E6%9B%B4,-%E3%81%93%E3%81%93%E3%81%A7%E3%81%AFprivate

・フィールドの場合
https://qiita.com/11295/items/773e7395889e05f605ae

・JavaのリファレンスやAPIの読み方も勉強した方が効率良さそう。
https://www.sejuku.net/blog/33352#:~:text=8%20%E3%81%BE%E3%81%A8%E3%82%81-,Java%E3%81%AE%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9%E3%81%A8%E3%81%AF,-Java%E3%81%AE%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9

・getDeclaredField()であれば修飾子関係なくフィールドを取得できるっぽい
https://pppurple.hatenablog.com/entry/2016/08/01/225120#:~:text=is(arrayContainingInAnyOrder(expected)))%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D-,getDeclaredField(),-getDeclaredField()%E3%81%A7%E3%81%AF%E3%80%81getField
 　
　

:メモ書き:
・こんな感じでフィールドをアクセス可能にできるっぽい
Field f = testClass.getClass().getDeclaredField("str");
f.setAccessible(true);

・privateとかの修飾子のものを他クラスで扱うには？
Classクラス,Methodクラス,Fieldクラスの
getDeclaredなんちゃら()とかを使って
.setAccessible(true)でアクセス可能にすれば
private,protectedでも扱えるようになるらしい。

　
　　
試しに作ってみたコード
環境：エクリプス、java11
```
package testreflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestReflection {

	public static void main(String[] args) {
		try {
		/* クラスの場合 */
			Class<?> clazz = Sample.class;
			// クラスの完全修飾子を取得 Class.forNameには完全修飾子がいるらしい
			String fqcn = clazz.getName();
			// クラスを見つける
			Class<?> sampleClass = Class.forName(fqcn);
		/* コンストラクタの取得 */
			// <?>を使ったためint.classで型を指定しないとエラーになる
			Constructor<?> constructor = sampleClass.getConstructor(int.class);
			// コンストラクタに100を渡す
			Object sampleInstance = constructor.newInstance(100);
			System.out.println(sampleInstance);
//			↓短縮版
//			System.out.println(Class.forName(Sample.class.getName()).getConstructor(int.class).newInstance(100));
//
		/* フィールドの場合 */
			// フィールドのvalueを取得
			Field valueField = sampleClass.getDeclaredField("value");
			// privateだからアクセス可能にする
			valueField.setAccessible(true);
			// フィールドに200をセット
			valueField.set(sampleInstance, 200);
			// フィールドの値の取得
			Object fieldObject = valueField.get(sampleInstance);
			System.out.println(fieldObject);
		/* メソッドの場合 */
			// getDeclaredMethod()であればprotecedでも取得できる
			Method multiMethod = sampleClass.getDeclaredMethod("multi", int.class);
			// アクセス可能にする
			multiMethod.setAccessible(true);
			// メソッドの実行
			Object ret = multiMethod.invoke(sampleInstance, 2);
			System.out.println(ret);

			// おびただしいほどの例外 短縮とか省けそうだけど？？
		} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException
				| IllegalAccessException | IllegalArgumentException | InvocationTargetException
				| NoSuchFieldException e) {
			e.printStackTrace();
		}
	}
}

class Sample {

	private int value;

	public Sample(int value) {
		this.value = value;
	}

	protected int multi(int value2) {
		return value * value2;
	}

	@Override
	public String toString() {
		return "Sample{" + "value=" + value + '}';
	}
}
```


# 【結論】
Classクラス,Methodクラス,Fieldクラスを使っていけばリフレクションができるらしい。

終わり。