隠しフィールド変数
下のようなクラスがあったとする。
public class Hogeo {
private Class cls = Hogeo.class;
private String class$0;
}
このクラス、実はコンパイルが通らない。
エラー内容は「Duplicate field Hogeo.class$0」。
class$0というフィールドが重複しているらしいけど、
ソースコード上では明らかに重複してない。
なんでだろ。
ちょっと調べるために、「private String class$0;」の部分を
コメントアウトして、下のようなコードでフィールド一覧を抽出してみた。
実行結果はこんな感じ。
public static void main(String[] args) {
Field[] fields = Hogeo.class.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(i + ": " + fields[i]);
}
}
なぜかClass型の変数class$0が存在してる〜。
0: private java.lang.Class test.Hogeo.cls
1: static java.lang.Class test.Hogeo.class$0
うーみゅ。
もうちょっと調べてみた。
フィールドやらメソッドやらはクラスファイル上ではAttribute
という情報を持っているらしい。
なので、こいつをJavassistで表示させてみた。
# Javassistの本来の使い方ではないけど、気にせず。
まず、てきとうコード。
そして、実行結果。
public static void main(String[] args) {
try {
CtClass ctCls = ClassPool.getDefault().get("test.Hogeo");
CtField[] ctFields = ctCls.getDeclaredFields();for (int i = 0; i < ctFields.length; i++) {
System.out.println(i + ": " + ctFields[i]);
List attrs = ctFields[i].getFieldInfo().getAttributes();for (int j = 0; j < attrs.size(); j++) {
AttributeInfo attrInfo = (AttributeInfo) attrs.get(j);
System.out.println(" " + attrInfo.getName());
}
}
} catch (NotFoundException e) {
e.printStackTrace();
}
}
をを。
0: test.Hogeo.cls:Ljava/lang/Class;
1: test.Hogeo.class$0:Ljava/lang/Class;
Synthetic
class$0の方にはSyntheticというAttributeがある。
Synthetic Attributeは、ここらへんに書いてあるやつっぽい。
http://java.sun.com/docs/books/vmspec/2nd-edition/html/ClassFile.doc.html#43817
さえない英語力で訳してみると、ソースコード上にないクラスメンバには
このAttributeが付けられるらしい。
なんかよくわからんけど、「foo.class」というコードは
クラスファイル上ではフィールド変数を使う形で表現されるんですかね。
メソッド内で「foo.class」と実装しても隠しフィールドが見えたので。
コンパイラの仕様みたいなのからわかるかなーと思ったけど
わたくしめの力では、ここらへんが限界っすorz
まぁ、class$0なんて変数名を使うことはないし、どうでもいい話題だなー。