[解決済み】Javaのジェネリックで<T>の代わりに<? extends T>が必要になるのはどんなときか、また切り替えることによるデメリットはあるか?
質問
次の例を考えてみましょう(JUnitとHamcrest matchersを使用)。
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
これはJUnitでコンパイルされません。
assertThat
のメソッドシグネチャを使用します。
public static <T> void assertThat(T actual, Matcher<T> matcher)
コンパイラのエラーメッセージは
Error:Error:line (102)cannot find symbol method
assertThat(java.util.Map<java.lang.String,java.lang.Class<java.util.Date>>,
org.hamcrest.Matcher<java.util.Map<java.lang.String,java.lang.Class
<? extends java.io.Serializable>>>)
しかし、もし私が
assertThat
メソッドのシグネチャになります。
public static <T> void assertThat(T result, Matcher<? extends T> matcher)
すると、コンパイルがうまくいきます。
そこで3つの質問。
- なぜ今のバージョンはコンパイルできないのですか?共分散の問題はなんとなくわかっているのですが、説明しようにも説明しきれません。
-
を変更することで何か不都合はありますか?
assertThat
メソッドからMatcher<? extends T>
? そうすると壊れるケースが他にもあるのでしょうか? -
を汎用化することに意味はあるのでしょうか?
assertThat
メソッドを JUnit で使用できますか?そのMatcher
クラスはそれを必要としないようです。JUnit はジェネリックで型付けされていない matches メソッドを呼び出すので、何もしない型安全性を強制しようとしているようにしか見えません。Matcher
は実際にはマッチしないだけで、テストは関係なく失敗します。安全でない操作は関係ありません(というか、そう見えます)。
参考までに、以下はJUnitの実装です。
assertThat
:
public static <T> void assertThat(T actual, Matcher<T> matcher) {
assertThat("", actual, matcher);
}
public static <T> void assertThat(String reason, T actual, Matcher<T> matcher) {
if (!matcher.matches(actual)) {
Description description = new StringDescription();
description.appendText(reason);
description.appendText("\nExpected: ");
matcher.describeTo(description);
description
.appendText("\n got: ")
.appendValue(actual)
.appendText("\n");
throw new java.lang.AssertionError(description.toString());
}
}
解決方法は?
まず、-に誘導する必要があります。 http://www.angelikalanger.com/GenericsFAQ/JavaGenericsFAQ.html -- 彼女は素晴らしい仕事をしています。
基本的な考え方は
<T extends SomeClass>
実際のパラメータが
SomeClass
またはそのサブタイプ。
あなたの例では
Map<String, Class<? extends Serializable>> expected = null;
Map<String, Class<java.util.Date>> result = null;
assertThat(result, is(expected));
あなたが言っているのは
expected
を実装している任意のクラスを表すClassオブジェクトを含むことができます。
Serializable
. あなたの結果マップでは
Date
クラス・オブジェクトを作成します。
resultを渡すときは
T
を正確に
Map
の
String
から
Date
クラスオブジェクトにはマッチしませんが
Map
の
String
であるものには
Serializable
.
一つ確認しておきたいのは、本当に
Class<Date>
でなく
Date
? のマップは
String
を
Class<Date>
は、一般的にはあまり便利とは言えないようです(保持できるのは
Date.class
のインスタンスではなく、値として
Date
)
一般化については
assertThat
を確実に実行できるようにすることです。
Matcher
というように、結果の型に合ったものが渡されます。
関連
-
[解決済み] JVMフラグCMSClassUnloadingEnabledは、実際に何をするのですか?
-
[解決済み] Eclipse デフォルトのフォント名
-
[解決済み] ストリングビルダー.イコール Java
-
[解決済み] JavaでFileFilterを作るには?
-
[解決済み] java.lang.IncompatibleClassChangeError: Mongo クラスを実装しています。
-
[解決済み] JavaにおけるMouseListenerとMouseAdapterの違いについて
-
[解決済み] Java- <T extends Comparable<T>>の意味?
-
[解決済み] スリーピング中のスレッドが割り込まれ、データベースへの接続が失われる
-
[解決済み] java swingアプリケーションでJCEがプロバイダBCを認証できない
-
[解決済み】Javaジェネリックの'E'、'T'、'?'の違いは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Jdbctemplate の文字列に対するクエリです。EmptyResultDataAccessException: 不正な結果サイズ:期待値1、実際0
-
[解決済み] Firebase クラスにシリアライズするプロパティが見つからない
-
[解決済み] XX:MaxDirectMemorySizeの既定値
-
[解決済み] double 型を Int 型に変換、切り捨て
-
[解決済み] Eclipse- Dynamic Web Module 3.0 で新しいプロジェクトを作成するときに Java 1.6 以降が必要なエラーが発生する。
-
[解決済み] java.lang.ClassNotFoundException: クラス com.ibm.db2.jcc.DB2Driver が Worklight プラットフォームまたはプロジェクトに見つかりませんでした。
-
[解決済み] 親から継承したメソッドの可視性を下げることができない [重複]。
-
[解決済み] スリーピング中のスレッドが割り込まれ、データベースへの接続が失われる
-
[解決済み] java.lang.ClassCastException: java.lang.Long を java.lang.Integer にキャストできない(java 1.6
-
[解決済み] java swingアプリケーションでJCEがプロバイダBCを認証できない