ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Java質問&情報提供サイトコミュのGenericsなキャスト

  • mixiチェック
  • このエントリーをはてなブックマークに追加
昔のコードを見ていたら、
以前友達と話題になったものを思い出しました。
(Tigerがリリースされた頃です)

題目は
「型パラメータを利用したキャストや型チェックはできない?」

事の発端は、
シリアライズしたオブジェクトを読み込んだ際に自動でキャストしたい。でした。
String str = load(inputStream); //これをしたい

次のようなコードが書ければよいのですが、
「obj instanceof T」の部分がコンパイルエラーになります。

public static final <T extends Object> T load(InputStream is) throws IOException, ClassNotFoundException {
 ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(new GZIPInputStream(is)));

 Object obj = ois.readObject();

 if (obj instanceof T) {
  return (T) obj;
 } else {
  throw new IllegalArgumentException("引数がおかしい");
 }
}
(注)インデントに全角スペースが入っています

で、その時はそれをJavassistというバイトコード変換ライブラリを用いて無理やり解いてみたのですが、そのコードをみつけました。
http://www.mickey.ai.kyutech.ac.jp/~stagesp/java/src/gcast.zip
Javassistのjarファイルも含めておいてあります。
GenericCastというクラスが私が作成したもので使い方は次のようになります。

String str = GenericCast.cast("str");
Integer i = GenericCast.cast(2);
Integer i = GenericCast.cast("str"); //キャストできない

解決手順の概要は次のとおりです。
castメソッド中で
? スタックトレースから呼び出し元クラスを取得
? 呼び出し元クラスのバイトコードからキャストと呼び出しの組み合わせを見つける
? キャストの型とメソッド引数の型をチェック

もっと簡単に出来る。何に使うの?等、
皆さんの意見を聞かせていただきたいなと思ってトピックをあげました。
ご意見いただければ幸いですm(_ _)m

コメント(3)

Javassistに関して、私はほぼ無知なので、
これがベストかどうかわからないのですが、
java.lang.Class#cast(Object)
を使うのが一番簡素な書き方になるのではないかと思います。
これをメソッド内部で使う場合、
メソッドの引数にClass<T>を追加しなければなりませんが、
その辺はやむを得ない部分ではないかな、って思ってます。
java.lang.Class#isInstance(Object)を用いれば、
instanceof演算子と等価な処理もできますし...

ちなみに、型パラメータとして与えられたTの用途は、
コンパイラが型チェックに使うことくらいで、
Tがどんな型を表しているのかによって
何らかの形で処理を分岐させるような処理をするには、
私の浅い経験の範囲では、
Class<T>のインスタンスがないと、
ちょっとできそうにない感じでした。
> ゆ〜ゆ〜さん、猫タカさん

ご意見ありがとうございます。

ランタイムにgenericsの情報が消えてしまう今の実装を考えると、クラスを渡すのが素直な解だという気がしますね。
「未踏の道」非常に参考になりました。
情報ありがとうございます!!

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Java質問&情報提供サイト 更新情報

Java質問&情報提供サイトのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング