悪あがきプログラマー

悪あがきを続けていきたい技術と書評なブログです。トレタでiOSエンジニアやってます。

toString()をリフレクションで書きたい。

debug用等でフィールドをtoStringするときは、まぁ適当に書くとこんな感じですね。

@Override
public String toString() {
	StringBuilder sb = new StringBuilder();
	sb.append("key:").append(key).append(",");
	sb.append("name:").append(name).append(",");
	sb.append("sex:").append(sex).append(",");
	sb.append("age:").append(age);
	return sb.toString();
}

実行結果

key:aaa,name:bbb,sex:ccc,age:ddd

でも、これだとフィールドがやたら多い場合に面倒です。
なにより、見栄えが悪い。。
ということで、リフレクションの使用を検討してみたいと思います。

リフレクションを使ってみよう

リフレクションのメリデメ

  • メリット:記述量が少なくなる。共通処理として抜き出せる。
  • デメリット:遅い。セキュリティマネージャにひっかかるかも?

Beanはとりあえず、こんなのを用意しました。

public class TestBean {
	private String key;
	private String name;
	private String sex;
	private String age;

さて、
フィールドをリフレクションで取得するには
java.lang.Class#getDeclaredFields()でjava.lang.reflect.Field[] を取得してやればいいらしい。

@Override
public String toString() {
	StringBuilder sb = new StringBuilder();
	Field[] fields = this.getClass().getDeclaredFields();
	for (Field field : fields) {
		sb.append(field.getName());
	}

	return sb.toString();
}

実行結果

keynamesexage

フィールド名がそのまま取れた。
そりゃそうか。ここからどうすればいいんだろう?


java.lang.reflect.Field#get(object)を使ってみる。

@Override
public String toString() {
	StringBuilder sb = new StringBuilder();
	Field[] fields = this.getClass().getDeclaredFields();
	for (Field field : fields) {
		try {
			sb.append(field.get(this));
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	return sb.toString();
}

実行結果

aaabbbcccddd

おお、出た!
整形してないので、ずらずら出てるだけだけど。。


あれ?
そういや、java.lang.reflect.Field#setAccessible(true)ってのをしないと、
privateフィールドへのアクセスは例外になるはずなんだが・・・?
試しに、入れてみても実行結果は変わらず。。


なぜ??


まぁ、いいか。

追記:
java.lang.reflect.Field#setAccessible(true)は、privaetフィールドへのアクセスを
許容するという宣言。
今回のサンプルでは、同クラス内のtoStringからprivateフィールドにアクセスしているため、
特に制限がない。(自クラス内からアクセス出来るのは当たり前)
なので、他のクラスのprivateフィールドにアクセスするときは、上記のメソッドで制限を
はずさなければいけない。



整形してみた。

@Override
public String toString() {
	StringBuilder sb = new StringBuilder();
	Field[] fields = this.getClass().getDeclaredFields();
	for (Field field : fields) {
		try {
			sb.append(field.getName() + "=" + field.get(this) + ", ");
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}

	return sb.toString();
}

実行結果

key=aaa, name=bbb, sex=ccc, age=ddd, 

最後のカンマはめんどくてとってないけど、いい感じ。


時間切れなので、今日はここまで。

次はフィールドが配列や、Beanの場合を考えてみよう。