Fight the Future

Java言語とJVM、そしてJavaエコシステム全般にまつわること

君は合成フィールドを知っているか!(Java)

君は合成メソッドを知っているか!(Java)に続いて第2弾。


前回はMethodクラスのisSynthetic()を調べたわけだけど、
そもそもisSynthetic()はMethodクラスのインタフェースであるMemberに定義されている。
Memberインタフェースを実装するクラスとして、Method、Field、Constroctorがある。


今回はフィールドについて調べてみる。
FieldがisSynthetic()である、つまり合成フィールドってなんだ?ってこと。
synthetic(合成)はコンパイラが自動的に作成するという意味。
ならば「合成フィールドとはコンパイラが作成するフィールド」ということになる。


ではどんなときにコンパイラはフィールドを作成するのか?
検索するとSunのサイトに解説があった。
http://java.sun.com/docs/books/tutorial/reflect/member/fieldModifiers.html
インナークラスを作成したときに、そのインナークラスに合成フィールドが作られることがあるらしい。


SunのサンプルはなんかEnumのやつも混じってるので、すっきりさせてみた。

import static java.lang.System.out;

import java.lang.reflect.Field;

public class Test {

	class Inner {
		String aaa;
	}

	public static void main(String[] args) throws Exception {

		try {
			Class<?> c = Class.forName("Test$Inner");

			Field[] flds = c.getDeclaredFields();
			for (Field f : flds) {
				out.format("%-8s [ synthetic=%-5b ]%n", f.getName(), f
					.isSynthetic());
			}

		} catch (ClassNotFoundException x) {
			x.printStackTrace();
		}

	}

}

TestクラスのインナークラスとしてInnerを定義する。
Innerには比較のためにフィールドを1つ定義する(aaa)。
main()メソッドではInnerクラスのClassを取得して、すべてのフィールドを出力する。
本来、Innerクラスにはフィールドとしてaaaしかないはず。
しかし、実行するとこうなる。

aaa      [ synthetic=false ]
this$0   [ synthetic=true  ]

定義した覚えがない「this$0」というフィールドを出力している。
そして、syntheticがtrueになっている。
つまり、これが合成フィールドのようだ。


こう記述があった。

the compiler will generate some synthetic fields which are needed during runtime. To test whether a field is synthetic, the example invokes Field.isSynthetic(). The set of synthetic fields is compiler-dependent; however commonly used fields include this$0 for inner classes (i.e. nested classes that are not static member classes) to reference the outermost enclosing class

Retrieving and Parsing Field Modifiers (The Java™ Tutorials > The Reflection API > Members)

この場合、インナークラスからもっとも外にあるエンクロージングクラスを参照できるように、合成フィールドが作成されるようだ。