tanamonの稀に良く書く日記

KEEP CALM AND DRINK BEER

enumにimplementsするとjavacがシンボルを見つけられなくなることがある件

バグレポートが出ていた。
http://bugs.sun.com/view_bug.do?bug_id=6330385
http://bugs.sun.com/view_bug.do?bug_id=6522780
http://bugs.sun.com/view_bug.do?bug_id=6724345

バグレポートにあった検証用コード

public class Test {
	public static void main(String[] args) {
		for (E e : E.values()) {
			e.m();
		}
	}
}

interface I {
	void m();
}

enum E implements I {
	X {
		public void m() {
		}
	}
}

java 1.6.0_17で実行した場合

C:\>java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
Java HotSpot(TM) Client VM (build 14.3-b01, mixed mode, sharing)

C:\>javac Test.java
Test.java:5: シンボルを見つけられません。
シンボル: メソッド m()
場所    : E の クラス
                        e.m();
                         ^
エラー 1

バグレポートの通りにエラーが出る。

java 1.7.0-ea-b59で実行した場合

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b59)
Java HotSpot(TM) Client VM (build 16.0-b03, mixed mode, sharing)

C:\>javac Test.java

JDK7だとエラーにならない。
(1.7.0-ea-b59はちょっと古いものなんだけど、新しいのでも通ると思われる)
追記:6724345のレポートにRelease Fixed 7(b39)とあった


ちなみに、enumを別ファイルにしておき、先にコンパイルされるようにすると、JDK6でもコンパイルが通るようになる。

Test2.java

public class Test2 {
	public static void main(String[] args) {
		for (E2 e : E2.values()) {
			e.m();
		}
	}
}

E2.java

public enum E2 implements I2 {
	X {
		public void m() {
		}
	}
}

interface I2 {
	void m();
}

これなら通る

C:\>javac E2.java Test2.java

これはダメ

C:\>javac Test2.java E2.java

JDK6系を使う場合には、コンパイル順序の考慮が必要らしい。

でも実際にはパッケージが違ったりすることがよくあるので、そういった場合でもenumクラスが先にコンパイルされるようにするには、パッケージ名やクラス名を意識しておかないといけないということになりそうです。面倒な話ですな。