僕は知らなかった。。。まだまだJava初心者だな。
出会い
S2のBeanDescImpl*1クラスを読んでいたらこういうソースがあった。
private void setupPropertyDescs() { ... if (MethodUtil.isBridgeMethod(m) || MethodUtil.isSyntheticMethod(m)) { continue; } ...
Bridge??Synthetic??
J2SE1.5から!?
で、MethodUtil*2のメソッドはこれ。
private static Method getIsSyntheticMethod() { try { return Method.class.getMethod("isSynthetic", null); } catch (final NoSuchMethodException e) { return null; } } private static Method getIsBridgeMethod() { try { return Method.class.getMethod("isBridge", null); } catch (final NoSuchMethodException e) { return null; } }
リフレクションのMethodクラスにisSynthetic、isBridgeメソッドがあるか調べてる。
そんなメソッドあったっけ。。。ある!しかもJ2SEの1.5から!http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/reflect/Method.html#isBridge()
橋渡し役のメソッド?合成メソッド?謎が深まる。。。
共変戻り値の実装にかかわっていた
この2つのメソッドはJ2SE1.5から導入された、共変戻り値にかかわっていた。
(共変戻り値はなんとか知ってたぜ!)
共変戻り値とは単純に言うと、オーバーライドするときに、スーパークラスで定義した戻り値の型のサブクラスの型を、オーバーライドしたメソッドで定義すること。
要はこういうこと。
public interface ReturnNumber { Number value(); } public class ReturnInteger implements ReturnNumber { public Integer value() { return Integer.valueOf(0); } }
インタフェースで定義したメソッドvalue()の戻り値はNumber。
それを実装したクラスでは戻り値をNumberのサブクラスであるIntegerで定義する。
これが共変戻り値。
もちろんコンパイルも実行も例外なくできる。
で、合成メソッドって?
こういう共変戻り値を使ったときなど、コンパイラが自動的にメソッドを作成することがあるらしい。
この自動的に作成したメソッドを合成メソッドという。
たとえば、共変戻り値を使ったときは、スーパークラスと同じ戻り値の型のメソッド(今までのオーバーライドのイメージ)がコンパイラによって作られる(戻り値の型を変えて実装したメソッドとは別に)。これが合成メソッド。
さらに、共変戻り値での合成メソッドは、内部的には新たに戻り値の型を変えたメソッドに処理を委譲する、という実装になっている。
なるほど!こうして共変戻り値を実現しているんだ!非常に納得。
最後にコードで実証
では本当に合成メソッドが作られているか、確認。
リフレクションを使う。さっきの2つのクラスで。
public static void main(String[] args) { Method[] methods = ReturnInteger.class.getMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; System.out.println(method); System.out.println("\tisSynthetic:" + method.isSynthetic()); System.out.println("\tisBridge:" + method.isBridge()); } }
実行するとこんな出力。
public java.lang.Integer ReturnInteger.value() isSynthetic:false isBridge:false public volatile java.lang.Number ReturnInteger.value() isSynthetic:true isBridge:true ...
(volatileはsynchronizedのゆるいのやつね。)
たしかにvalue()メソッドが2つあり、インタフェースで定義した方はisSynthetic()もisBridge()もtrueを返してる。
まだまだJavaで知らないことがたくさんあるんだな。