Effective Javaを読むチャレンジ-項目29その2-

項目29の内容が全然理解できないので・・・

いろいろ調べていましたが、本書の展開が急すぎてやはり分かりにくいです。そこで、本書が参考にしている「Generics in the Java Programming Language」というGilad Bracha氏の論文を最初に見るのが早いと思いました。該当する話題はその論文の8章です。

Generics in the Java Programming Language (PDF)

Class Literals as Run-time Type Tokens

「実行時型トークンとしてのクラスリテラル」という見出しで始まるこの章は、JDK 1.5の変更点のなかで、java.lang.Classがジェネリック型になったことで興味深い使用例をもたらすと始まります。

では、Class<T>のTは何を表すのでしょうか。それは、そのクラスのオブジェクトが表している型です。Class<String>はString.classというクラスリテラルと同じです(代入可能でもあります)。ちなみに「Class<Number> numClass = Integer.class;」といったコードは書けません。ジェネリックスのパラメータ化された型は不変です。

ClassクラスのnewInstanceメソッドは、Class<T>のTについてのインスタンスを返します。この性質を利用した例として、DBに対してSQLを実行し、その結果をコレクションに格納して返すユーティリティメソッドを考えます。その論文では一般的にはこうするとあります。

ここで例えば従業員データを保持するテーブルがあったとします。従業員テーブルは名前、年齢、生年月日、所属・・・など情報を持っています。EmpInfoクラスはその従業員テーブルの列をフィールドとして持ち、従業員テーブルの行データを保持するクラスです。

そのEmpInfoクラスのファクトリを実装します。

最終的にユーティリティメソッドの呼び出し側はこうなります。

これは無名クラスを使って次のようにも書けます。

この論文では上記の方法には問題があると言っています。簡単に書くと以下のようになります。

  • 無名クラスを使ってファクトリクラスを実装する冗長なコードを書くか、
  • すべてのテーブルのファクトリクラスを作成してユーティリティメソッドに渡さなくてはいけない

そこで、クラスリテラルを使うとこれらの問題が解決されると言っています。まずはジェネリックスなしのクラスリテラルを使った解決例です。

ところがこの方法は原型を使用しているため、型安全ではありません。そこでジェネリックスを使用するのです。

ジェネリックスを使うことで型安全になり、Class#newInstanceメソッドのおかげで余計なファクトリメソッドも書かなくて済みました。これが本書の3段落目の後半の部分で参考にされた論文の内容です。

この実装においてユーティリティメソッドの引数に渡した「EmpInfo.class」がどのような役割を果たしたかを考えます。「EmpInfo.class」は、ユーティリティメソッドの型パラメータTの実型パラメータになります。実型パラメータはコンパイル時にその型を使ったコードに変換されます。

ここで、ユーティリティメソッドの引数である「Class<EmpInfo>」は、型消去により実行時には型パラメータが消去されると思うかもしれません。ところが「Class<EmpInfo>」は「EmpInfo.class」でもあるため、実行時にその型情報を残しています。その性質を利用し、newInstanceメソッドは型情報を使ってインスタンスを生成することができています。

このように、クラスリテラルがコンパイル時と実行時の型情報を伝えるためにメソッドに渡された場合、それは型トークン(type token)と呼ばれます。

結局、本項目の序盤の話は何なのか

本項目の2段落目はだいたい上記の論文の話が元になっていると思います。本書では、データベースのすべての列にアクセス云々・・・の話はもう終わっていて、型トークンの別の使用例としてFavoriteクラスのサンプルを紹介しています。私が話がつながっていないと混乱していたのは型トークンを知らなかったために話の内容が見えてなかったからですね、反省です・・・。

このFavoriteクラスが型安全な異種コンテナーパターンの例ということです。何とか本筋に戻れそうです・・・。

広告
  • LINEで送る