質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

5038閲覧

境界型ジェネリクスで型を取得したい

lupus_dingo

総合スコア257

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2017/02/04 08:49

お世話になっております。
Daoクラスをテンプレート化するために親クラスを作成しているのですが
境界型ジェネリクスで型を指定する際に以下のEからどのように型を取得すればいいのでしょうか?

lang

1 2abstract public class BaseDao<E extends BaseEntity> { 3 4 protected static void findAll(String sql) throws Exception { 5 Connection con = getConnect(); 6 7 RowProcessor rp = new BasicRowProcessor(new MyBeanProcessor()); 8 QueryRunner qr = new QueryRunner(); 9 10 ResultSetHandler<List<E>> h = new BeanListHandler<E>(E.class, rp);// E.classがコンパイルエラー 11 List<E> list = qr.query(con, sql, h); 12 con.close(); 13 } 14~省略~ 15}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

クラス名などから察するに、Commons-dbutilsをお使いなのだと思いますが(違っていたらすみません)

Commons-dbutilsでDAOを作る場合には、便利な実装例があります。
Apache Commons公式|DbUtils: JDBC Utility Component Examples

クエリを投げるクラスと、結果1行ごとに制御するハンドラとを分けると、例えば以下のようにすると良いでしょうか。

あとは、型情報(ここでは T)はインスタンス化できないので、引数に追加してあげると良いでしょう。

java

1import java.sql.SQLException; 2import java.util.List; 3 4import javax.sql.DataSource; 5 6import org.apache.commons.dbutils.QueryRunner; 7import org.apache.commons.dbutils.ResultSetHandler; 8import org.apache.commons.dbutils.handlers.BeanListHandler; 9 10public class BaseDataAccessObject<T> { 11 12 private DataSource dataSource = null; 13 14 public List<T> findAll(String queryString,Class<T> clazz) throws SQLException { 15 ResultSetHandler<List<T>> h = new BeanListHandler<T>(clazz); 16 17 QueryRunner run = new QueryRunner(dataSource); 18 19 List<T> result = run.query(queryString, h, "PlaceHolder"); 20 21 return result; 22 } 23}

投稿2017/02/04 09:56

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lupus_dingo

2017/02/04 10:10

回答ありがとうございます。 クラス自体を引数に渡すという発想がなかったので勉強になりました。 他の方の回答も参考にさせていただき、実装に反映させていただきます。 ありがとうございました。
guest

0

  1. 一番簡単な方法

このクラスのコンストラクターに派生クラスからEのクラスを渡してこのクラスのフィールドに覚えておく。

  1. リフレクションを使う(条件付き)

細かな条件を忘れたのですが・・・(^^;
例えばこのクラスの派生クラスをnew DerivedDao<DerivedEntry>() {};のように無名クラスとして生成してやるとリフレクションで型引数のクラスを実行時に参照できます。無名クラスにせずにインスタンスを生成すると型が消去されてしまうのでリフレクションでも参照できません。

java

1abstract public class BaseDao<E extends BaseEntity> { 2 final Class<E> classE; 3 4 BaseDao() { 5 ParameterizedType superType = 6 (ParameterizedType)getClass().getGenericSuperclass(); 7 Type[] atvs = superType.getActualTypeArguments(); 8 classE = (Class<E>)atvs[0]; 9 } 10}

このコードではBaseDaoを直接継承したクラス(無名クラスとか)しかないと前提を置いてます。
派生の派生・・・というふうに継承が深くなるともう少し配慮が必要だと思います。

無名クラスで取れるのでclass DerivedDao extends BaseDao<DerivedEntity> { ... }のように普通に派生クラスを定義しても同じ方法でクラスが参照できると思います。

投稿2017/02/04 09:14

編集2017/02/04 09:20
KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lupus_dingo

2017/02/04 09:33

回答ありがとうございます。 ただ見慣れないクラスがいろいろ出てきてちょっと理解しきれません^^; Daoの基底クラスでコネクションからクエリ実行などの共通処理を行い、 子クラスではSQLの作成のみを行いたい場合通常はどのように設計するのが正しいでしょうか? 参考になりそうなサイトでもあれば教えていただきたいです。
KSwordOfHaste

2017/02/04 10:16

残念ながら自分はDBアプリの経験が乏しすぎるので回答に示した「言語仕様上のテクニック」以上のアドバイスはできそうもないです。自分の場合は「あるインターフェースの個別クラスに対して生成、加工、出力までの共通の処理パターンがあって生成もジェネリックスクラス内で書けるかやってみた」といった動機だったのです。他の方のコメントを見て自分も勉強したいと思います。
lupus_dingo

2017/02/04 10:26

回答ありがとうございます。 お互い頑張りましょう。
guest

0

ベストアンサー

基本的はジェネリクスは抽象的に扱うものであって実態やクラスは取得できません。
必要になってしまった場合には設計を見直すべきです。

一応裏技的な解決策はありますが、あまりいいソースとは言えません...

java

1Class<?> clazz = this.getClass(); 2Type type = clazz.getGenericSuperclass(); 3ParameterizedType pt = (ParameterizedType)type; 4Type[] actualTypeArguments = pt.getActualTypeArguments(); 5Class<?> entityClass = (Class<?>)actualTypeArguments[0];

追記

java

1abstract public class BaseDao { 2 3 protected static <E extends BaseEntity> void findAll(String sql) throws Exception { 4 Connection con = getConnect(); 5 6 RowProcessor rp = new BasicRowProcessor(new MyBeanProcessor()); 7 QueryRunner qr = new QueryRunner(); 8 9 ResultSetHandler<List<E>> h = new BeanListHandler<E>(getEntityClass(), rp);// E.classがコンパイルエラー 10 List<E> list = qr.query(con, sql, h); 11 con.close(); 12 } 13 14 protected abstruct <E extends BaseEntity> Class<E> getEntityClass(); 15~省略~ 16}

とかですかね?実装クラスではgetEntityClass()を記載する必要がありますが、クラスの総称型を書く必要がなくなります。

投稿2017/02/04 09:03

編集2017/02/04 09:54
7tsuno

総合スコア310

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lupus_dingo

2017/02/04 09:36

回答ありがとうございます。 他の方にも同じ質問になってもうしわけないのですが、 Daoの基底クラスでコネクションからクエリ実行などの共通処理を行い、 子クラスではSQLの作成のみを行いたい場合通常はどのように設計するのが正しいでしょうか? サンプルが載っているようなサイトがあったら教えていただきたいです。
7tsuno

2017/02/04 09:49

Eをクラスとして欲しいのであれば、抽象メソッドなどで取得するほうがいいのではないでしょうか? 回答に追記します。
lupus_dingo

2017/02/04 10:08

回答ありがとうございます。 なるほど参考になります。 こちらと他のアドバイスをからどれを採用するか考えようと思います。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問