W.I.S. Laboratory
menu-bar

Java


Javaでダックタイピングをしてみる

Javaはジェネリックメソッドが使える。
C++でいうところの関数テンプレートだ・・と思いきや、挙動がなんか違う。
C++のように静的ディスパッチしてくれると思いきや、動的ディスパッチでジェネリックメソッドを実現しているっぽい。
コンパイラがメソッドを量産してオーバーロードしてくれるわけではなく、受け取る型の共通の親クラスまで遡ってその型にアップキャストして受け取る、という動きをするらしい。
例えば、IntegerとDoubleが受け取れるジェネリックメソッドを作った場合、Number型として受け取るメソッドとしてコンパイルされる、という感じになるようだ。
何も継承していないユーザー定義型(自分で作ったクラスのインスタンス)だと、当然Object型として受け取ることになる。
つまりジェネリックメソッド内では引数の型情報が失われてしまっているので、受け取ったオブジェクトのフィールドやメソッドにアクセスできないという厄介な問題が発生する。

「どんなオブジェクトでも何でも来い」というメソッドは作れるのだが、受け取った後は「どこに何があるのか知らんけど」という状態だ。
ちなみにintやlongなどのプリミティブ型でも、受け取り時にIntegerやLongにラップ(AutoBoxing)されるので、NumberやObjectとして受け取ることになる。(どこまで遡るかは他にどんな型を受け取るのかで変わってくる)

とはいってもさすがに自分が何クラスのインスタンスなのかという情報は残っているので、instanceof演算子で元のクラスを逐一調べてはそれぞれの型にダウンキャストし、フィールドやメソッドにアクセスすれば、なんとかダックタイピングのような処理が書ける。
素直に同名メソッドを複数書いてオーバーロードするのとどちらがマシなのかはなんとも言えない感じ。
C++よりも徹底したオブジェクト指向型言語なので、すべての型には必ず共通の親クラスがあり、それがある故に可能になった仕様なのだろうと思う。
C++には真似のできないことではあるが、逆に言うとこれがあるので律儀にオーバーロードして静的にメソッドを量産しなくてもどんな型でも受け取れるメソッドが作れた、というわけなのだろう。


[ 戻る ]
saluteweb