LoginSignup
0
0

More than 1 year has passed since last update.

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

Last updated at Posted at 2022-05-13

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クラスを使っていけばリフレクションができるらしい。

終わり。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0