Javaのクロージャいじってみた。(2)
4.自動でインタフェース継承
・型推論
クロージャで記述すると自動的にインタフェースを継承してくれる。
いわゆる型推論ていうの?
いじってみた限りでは、以下の2つの記述で自動的に継承してくれる
ことは確認した。他のケースはしらん。
(1) 引数埋め込みで記述。
(2) クロージャの戻り値の型を継承したいインタフェース型で記述。
・継承した場合メソッドはクロージャ型のinvoke()ではなく、
各インタフェースのメソッドとして扱われる。(内部処理的にはinvoke()
ぽいメソッドが生成されている模様。)
・継承(実装)できるのはインタフェースだけで、抽象クラス/クラスは
継承できなかった。(コンパイルエラーになる)
ソースコード
逆コンパイルコード
・(1)(2)のように直接記述することはできるが、一旦クロージャ型で
受け取ったものを、各インタフェース型の変数/引数に渡すことは
できない。
例:
こんな定義インタフェースと利用処理があるとする。
以下のような書き方は代入の場所でエラー。
このときは {String=>}型 ではなく Closure<String>型 よこせ
というコンパイルエラーが出る。
以下のような書き方はOK。
・型推論
クロージャで記述すると自動的にインタフェースを継承してくれる。
いわゆる型推論ていうの?
いじってみた限りでは、以下の2つの記述で自動的に継承してくれる
ことは確認した。他のケースはしらん。
(1) 引数埋め込みで記述。
(2) クロージャの戻り値の型を継承したいインタフェース型で記述。
・継承した場合メソッドはクロージャ型のinvoke()ではなく、
各インタフェースのメソッドとして扱われる。(内部処理的にはinvoke()
ぽいメソッドが生成されている模様。)
・継承(実装)できるのはインタフェースだけで、抽象クラス/クラスは
継承できなかった。(コンパイルエラーになる)
ソースコード
Functor<Integer> func = {Integer i => (int)(i * 2.4 + 68)};
逆コンパイルコード
// 呼び出し側
obj._fld1 = _2B_INSTANCE0;
// 定義側
// 定数メンバとして定義される
public static final _cls2 _2B_INSTANCE0 = new Functor() {
// 戻り値型に継承されてる --> ~~~~~~~~~
public final int _2B_invoke(Integer integer)
{
return (int)((double)integer.intValue() * 2.39...9D + 68D);
}
// ジェネリクスの場合、ブリッジメソッドもちゃんと生成されてる。
public final Integer calc(Integer integer)
{
return Integer.valueOf(_2B_invoke(integer));
}
public volatile Object calc(Object obj)
{
return calc((Integer)obj);
}
}
・(1)(2)のように直接記述することはできるが、一旦クロージャ型で
受け取ったものを、各インタフェース型の変数/引数に渡すことは
できない。
例:
こんな定義インタフェースと利用処理があるとする。
public interface Closure<T> {
public void apply(T t);
}
public class Loop {
public static <T> void foreach(List<T> list, Closure<T> closure) {
...
}
}
以下のような書き方は代入の場所でエラー。
{String=>} println = {String str => System.out.println(str) };
// ×
Closure<string> closure = println;
// ×
Loop.foreach(list, println);
このときは {String=>}型 ではなく Closure<String>型 よこせ
というコンパイルエラーが出る。
以下のような書き方はOK。
// ○
Closure<string> = {String str => System.out.println(str) };
// ○
Loop.foreach(list, {String str => System.out.println(str) });
コメント