かつのりさんの「OpenJDKに言語機能を追加するプロジェクト」
がインスパイア元。
JavaにはC言語の関数ポインタやjavascriptの関数オブジェクトのような構文がありません。
メソッドそのものを指し示す機能というものがないのですね。
ではコールバックしたい場合などはどうするのでしょうか?
Javaではinterfaceを使います。
Javaのinterfaceはさながら実装を持たない完全な抽象クラスといった様相ですが、
型安全で継承可能な関数ポインタという側面があると私は考えています。
C言語での関数ポインタは
int (*p) (int num);
といったように、「戻り値の型 (*ポインタ名) (引数);」形式で宣言します。
C言語では引数と戻り値が合致していればよい、という程度に型安全です。
引数と戻り値の合致だけなので、根本的に設計の違う関数でも型さえあれば代入可能なわけです。
javascriptに至っては型安全など存在しない。
Javaで関数ポインタのようなことをしたい場合はまず、interfaceの定義を行います。
public interface Hoge {
/**
* 何らかの意図を持って設計されたメソッド
* @param i 引数
* @return 戻り値
* @throws HogeException 例外
*/
int hoge(int i) throws HogeException;
}
そして、このinterfaceの実装をもつクラスにimplements宣言をしてやるわけです。
これによって引数と戻り値が同じで、かつ、例外のthrowに対しても同様の定義がされた、
同じ目的で設計されたメソッドという型安全となっているわけです。
例えばなんらかのコールバックを行いたい場合、コールバック用のinterfaceを宣言し、
そのinterfaceの実装を渡すことでコールバックが可能となります。
// 無名クラスを使ってコールバックの実装を作成
Hoge hoeg = new Hoge(){
/** コールバックの実装 */
@Override
public int hoge(int i) {
return i;
}
};
コールバックするメソッド(hoge);
さらに、関数ポインタの場合は、単一の関数へのポインタでしたが、interfaceの場合は複数のメソッドを定義できますから、
関数ポインタよりもやれることの幅が広いわけですね。
interfaceは他のinterfaceを継承することもできますし。
ただ、その分、宣言がちょっと面倒だというのはあると思います。
interfaceの起源についてはカレーなる辛口Javaな転職日記の記事の議論を私は支持します。
Objective-Cに類似の機能性があったと聞きますが、このような形で昇華されたのはJavaではないでしょうか。
そういうわけで、私はJavaに関数ポインタなどいらないと考えています。
しかし、確かに宣言の煩雑さというのはあるわけですから、
単一のメソッドを持つinterfaceを記述するときのシンタックスシュガーはあるいは必要なのかもしれませんね。
投稿日時 : 2007年12月20日 11:54