- PR -

ジェネリックで動的に型の指定をしたい

1
投稿者投稿内容
しんい
ベテラン
会議室デビュー日: 2005/09/01
投稿数: 55
投稿日時: 2008-02-19 13:44
お世話になっております。

ジェネリックのパラメータを動的に与えたいのですが、仕様上可能なのでしょうか。

以下のようなクラスがあったとします。(フィールドやメソッドは割愛します。)
class Sample<T>

メソッドの中で、以下のようにパラメータ<T>を動的に与えたいのです。
public void test(int type){
  Sample<getType(type)> sample = new Sample<getType(type)>();
}
public【※】getType(int type){
  switch(type){
  case 0:return Integer;
  }
}
【※】は型がわからないので仮に入れております。

どなたかご教授頂ければ幸いです。
よろしくお願い致します。


申し訳ございません。
件名が漠然としていたので修正しました

[ メッセージ編集済み 編集者: しんい 編集日時 2008-02-19 13:48 ]
ranco
大ベテラン
会議室デビュー日: 2007/11/02
投稿数: 112
投稿日時: 2008-02-19 14:27
Javaのジェネリクスはコンパイラに対する機能ですから、ランタイムの決定機能は皆無です。
otf
ベテラン
会議室デビュー日: 2006/08/04
投稿数: 91
投稿日時: 2008-02-19 14:32
リフレクションを使えばできないこともないと思います。
ですが、動的に型を選択するということは
コンパイル時にT型を推論できません。
つまりT型に対してタイプセーフなコードは書けなくなります。

それでしたら
コード:
Sample<Object>


で十分だと思います。

またはT型になりうる型からインターフェースIを抽出して
コード:
Sample<I>


とすればタイプセーフなコードが書けます。
nagise
ぬし
会議室デビュー日: 2006/05/19
投稿数: 1141
投稿日時: 2008-02-19 15:40
ナンセンスなのでは?

コード:
Sample<getType(type)> sample = new Sample<getType(type)>(); 



が仮に可能だったとしましょう。
sampleはSample型の変数ですが、ジェネリクスの型パラメータが
コード上では不明ですから、Sample型に

コード:
public T getValue() { ... }



というメソッドが定義されていたとしても、

コード:
Object o = sample.getValue();



としか受け取りようがない。
Sample型の外部にこの型パラメータが波及しない、Sample内部だけで用いたいなら、

コード:
public Sample<? extends Object> getType(int type){
  switch(type){
  case 0:return new Sample<Integer>();
  }
} 



てなことも可能だけど、そもそも型をintで表現するようにしているのが疑問。
型 → int値とせず、もとの部分で型をジェネリクス型として渡すべき。
かつのり
ぬし
会議室デビュー日: 2004/03/18
投稿数: 2015
お住まい・勤務地: 札幌
投稿日時: 2008-02-19 16:14
何を持って「動的」というのは難しいですが、
動的に渡すには引数をClass<? extends T>にするとよいです。

ユースケースに対する解決方法はいくらでもあるので、
何故そういうことがしたいのか、
その経緯がわかるような利用元コードが知りたいです。

コード:
public void test(int type){ 
  Sample<getType(type)> sample = new Sample<getType(type)>(); 
}


は、単純に見るだけだと、
コード:
public void <T> test(Class<? extends T> type){ 
  Sample<T> sample = new Sample<T>();
}


になりますね。
しんい
ベテラン
会議室デビュー日: 2005/09/01
投稿数: 55
投稿日時: 2008-02-19 19:42
rancoさん、otfさん、nagiseさん、かつのりさん、ご返答有難うございました。

勉強不足な状態で質問してしまい、申し訳ないです。

かなり局所的なコードを書いてしまいましたが、実際に運用する形式については以下の通りです。
抽象的に説明する自信が無いので、実際に開発しているアプリケーションを基に説明させて頂きます。
【アプリケーションの内容】
EclipseRCPで開発しています。従ってSWTを基本としております。
【目的】
SWTのControl等を組み合わせて、オリジナルのControlやクラスを作成しています。
DB等との連携も考慮して、必要なデータを各Controlに保持させます。
abstractクラスを用いて、オリジナルのControlに共通のメソッドやフィールドを保持させています。
フィールドの型はジェネリックにて指定します。

◆Inputインターフェイス
public interface Input<T> {
void set(T data);
T get();
}

◆InputControlクラス
public class InputControl implements Input<T>{

}

◆Dayクラス
public class Day extends InputControl<Calendar>{
   Calendar calendar;
   public void set(Calendar calendar){
     this.calendar = calendar;
   }
   public Calendar get(){
     return calendar;
   }
}


今回使用するのは、Tableのカラムヘッダーに対して、この方式を適用しようと思っています。
カラムヘッダーをクリックすると並び替えか絞り込み用のウィンドウが展開されます。
その際、並び替えをするのであれば、ジェネリックで指定された型を判別して、
数値や文字列の並び替えを適切に行います。(下記のgetType()で判別)
(数値を文字列とみなして並び替えをすると、500と1000では1000の方が小さいとみなされる為)

◆Columnクラス
public class Column implements Input<T>{
   T data;
   
   public void set(T data){
     this.data = data;
   }
   public T get(){
     return data;
   }
   public String getType(){
     reuturn data.getClass().getSimpleName();
   }
}

次に、各アプリケーションのデータをサーバーから都度ダウンロードさせるようにします。
例えば、public static final int product = 1;等の定数を設定し、int[]に入れ、サーバーから取得するのです。

◆createColumnメソッド
public Column createColumn(int type){
   switch(type){
   case 1:return new Column<Integer>();
   case 2:return new Column<String>();
   default:return new Column<Calendar>();
   }
}

ここまで、ジェネリックに対して問題はありません。
もちろん、実際のプログラムには、Columnに名前等を入れたりしますが割愛しております。

今回、この部分に対して拡張を加えようとした時に、どうすれば良いのか分からない状態になりました。

先程のような定数(public static final int product = 1)とオリジナルControlの生成を関係づけました。
◆createControlメソッド
public Control createControl(int type){
   switch(type){
   case 0:return new Day();()
   default:return new OriginalControl();
   }
}

ColumnクラスにInputControlを関係づけました。
◆Columnクラス(変更)
public class Column implements Input<T>{
   T data;
   InputControl<T> inputControl;

   public Column(InputControl<T> inputControl){
     this.inputControl = inputControl;
   }
   
   public void set(T data){
     this.data = data;
   }
   public T get(){
     return data;
   }
   public String getType(){
     reuturn data.getClass().getSimpleName();
   }
}

◆createColumnメソッド(変更)
public Column createColumn(int type){
   Control control = createControl(int type);
   return new Column(control);
}

この部分で、createColumnメソッドにて生成されたControlの保持する型(Calendar)をColumnにも適用したいと考えました。
そこでcontrol.get().getClass()....と色々型を抜き出してみたのですが上手くいきませんでした。

かなりの長文になってしまい申し訳ないです。
ご指摘頂けると幸いです。
よろしくお願い致します。
kuma
大ベテラン
会議室デビュー日: 2004/02/25
投稿数: 110
投稿日時: 2008-02-19 20:20
引用:

しんいさんの書き込み (2008-02-19 19:42) より:

この部分で、createColumnメソッドにて生成されたControlの保持する型(Calendar)をColumnにも適用したいと考えました。
そこでcontrol.get().getClass()....と色々型を抜き出してみたのですが上手くいきませんでした。



Controlの保持する型の何を使用したいのですか?
Columnはそれをどうしたいのですか?(適用の意図が不明)

引用:

先程のような定数(public static final int product = 1)とオリジナルControlの生成を関係づけました。
◆createControlメソッド
public Control createControl(int type){
   switch(type){
   case 0:return new Day();()
   default:return new OriginalControl();
   }
}

ColumnクラスにInputControlを関係づけました。
◆Columnクラス(変更)
public class Column implements Input<T>{
   T data;
   InputControl<T> inputControl;

   public Column(InputControl<T> inputControl){
     this.inputControl = inputControl;
   }
   
   public void set(T data){
     this.data = data;
   }
   public T get(){
     return data;
   }
   public String getType(){
     reuturn data.getClass().getSimpleName();
   }
}




ColumnのdataとinputControlに相関関係はないのですか?
1

スキルアップ/キャリアアップ(JOB@IT)