Javaのジェネリクスで,T.class や new T() ができず悩んだ話 (型パラメータのインスタンス化に関し、フレームワーク設計からケーススタディ)
Javaのジェネリクスで,型パラメータ T のインスタンスが欲しくなったことはあるだろうか?
昨今のオブジェクト指向プログラミングにおいて,ジェネリクスは必須の基本文法だ。
扱う対象のクラスが抽象化されて汎用的になりつつ,なおかつ型安全性が確保される。
そのおかげで,処理の重複や分岐をコーディングする必要が無くなり,コード量が驚異的に削減される。
そういう基本的な原則を踏まえると,
- 「型パラメータのインスタンスが欲しい」
というシチュエーションは,Javaのジェネリクスの本来の導入目的に真っ向から逆らう。
なぜなら,ジェネリクスは型を抽象化して透過的に扱えるようにするための機構なのだから,
せっかく抽象化した物をわざわざ具体化してどうするというお怒りを生む事になるのだ。
頑張って詳細なクラス情報を「T」でパラメータ化して具体性を隠ぺいしたにも関らず,
その T に対して .class で具体的な Class を取得しようと試みたり,new で現物のオブジェクトを生成してしまう。というのは,おかしい。
また,総称型 T は,newしちゃったが最後だ。
そこまで単なるパラメータで済んでいたものが,new 以降は具体的なオブジェクトとしてインスタンス化されてしまう。
そして,それ以降は「個別の具体的なオブジェクトの性質と付き合う」必要が生じてしまう。要は,抽象性が損なわれる。
だから new T() があってはならない。
こう考えるのは極めて自然であり,Java使いとして正統で,まっとうな反応でもある。
だから一般的に考えて,「T.class とか new T() が欲しい」などという発想は,
例えるならJavaで手続き型プログラミングをするかのような,あってはならない禁じ手のアンチパターンということになる。
したがって,そういう発言をすると「いったい何を考えてるんだ」という旨のツッコミを頂く事になる。
ジェネリクスでT.classやnew T()できないとさんざん嘆き,ver0.2のORM構成となったが,実は型パラメータのClass型は裏技的に取得できる。「Java変態文法最速マスター」を参照。これはver0.3でfixしよう。ユーザ URL
ぶっちゃけるとT.class やnew Tしたいケースは設計が悪いのだと思う。それを使う妥当なシチュエーションが候補があれば是非教えて欲しい。検討したい QT "@lang_and_engine: ジェネリクスでT.classやnew T()できないとさんざん嘆き"
お。このコードはいいな。ちょっとフォークしてみたい"@lang_and_engine: ジェネリクスでT.classやnew T()できない URL"
この基本的かつ貴重なツッコミを下さった @nagise 氏は,Hatena上では id:Nagise 氏であり,Web上でジェネリクスについて非常に多様な情報発信をして下さっている。
私自身,プログラミングで調べ物をする際に,普段からnagise氏の執筆した情報にたどりつく事が日常的によくある。
そしてとても勉強になる。
このお方は,なんとtwitterの自己紹介欄で・・・
- ジェネリクスを愛するさすらいのJavaプログラマ
と名乗っている。
(プログラミングの一分野について「○○を愛する」と公言できるというのは,敬服すべき事ではなかろうか?)
さらにすごいのが,保有しておられるブログ(複数)に「ジェネリクス」という独立したカテゴリを設け,そのトピックを詳細に論じて下さっている点。
プログラマーの脳みそ / Generics
http://d.hatena.ne.jp/Nagise/archive?...
凪瀬 Blog / ジェネリクス
http://blogs.wankuma.com/nagise/categ...
おかげで,ネット越しに情報収集する技術者にとって大助かりだ。
上記のWebページの情報は,Effective Java(第2版)の第5章の補遺として利用させて頂くのがよいと思う。
ここまでの情報を前提とした上で,タイトルの質問を考えてみよう。
ここから先が本論となる。
Javaのジェネリクスで,T.class とか new T() のようなコードが必要になる妥当なケースは存在するのか。
また,Java言語を使いつつもそういったニーズに応えることは,果たして技術的に可能なのか。
氏のツイートを再度引用:
「ぶっちゃけるとT.class やnew Tしたいケースは設計が悪いのだと思う。
それを使う妥当なシチュエーションが候補があれば是非教えて欲しい。検討したい
QT "@lang_and_engine: ジェネリクスでT.classやnew T()できないとさんざん嘆き"」
システム開発で新しい事をやろうとすると,どうしても試行錯誤が伴う(特に開発のパラダイムを変えようとあがく場合はなおのことそうなる)ので,あくまでも現時点での状況に基づく回答となるが,ここでその答えを述べてみる事にする。
思考の過程を書き記しておけば,のちのちの別のクラス設計にフィードバックする点で後学のためにも有益だろうし・・・。
どのような思考回路で,T.class やnew T のニーズが生まれるのか
Javaで一般的なプログラムを書いている限り,
パラメータ化された型 T に対して T.class や new T() しようなどと考えるべきではない。
この点は,もう既に述べた。
では,作ろうとしているのが一般的なアプリケーションではなく,汎用的なクラスライブラリやフレームワークである場合は,どうなるか。