6

バックグラウンド

この質問は、Java 開発者と Android 開発者の両方を対象としています。

Android では、Viewから拡張されたものを返し、 Checkableを実装する関数が必要です。どちらも Android API の一部です。

私が試したこと

ここやインターネット上の他の場所を少し検索した後、次の解決策を見つけました。

private <T extends View & Checkable> T get() {
    return (T) mView;
}

mView は View を拡張する任意の型であることに注意してください (そしてたくさんあります) が、それらの型だけが存在するため、Checkable を実装することを保証します。

これは "Type safety: Unchecked cast from View to T" という警告を表示しますが、それは問題ではありません。問題は、この方法を正しく使用できないことです。たとえば、次のようになります。

View v=get(); //this works fine
Checkable c=get(); // this shows error

2 行目にエラーが表示されます。

範囲の不一致: タイプ ... の汎用メソッド get() は、引数 () には適用できません。推測されたタイプ Checkable&View は、境界付きパラメーターの有効な代替ではありません

そこで、「&」の代わりに「,」を使ってみました。同じエラー。

ただし、「、」を使用して順序を逆にすると、「The type parameter View is hide the type View」という警告が表示され、両方の行が正常に機能します。

これはコードです:

private <T extends Checkable, View> T get() {
    return null;
}

private void foo() {
    final View v = get(); // this works fine
    final Checkable c = get();// this works fine too
}

ただし、返された型を他の関数に送信すると、クラスとインターフェイスを拡張するものとして型自体が取得されず、常に (View に) キャストする必要があります。

質問

それを行う正しい方法は何ですか?

最後に示した方法が正しい場合、なぜ警告が表示されるのですか? 拡張するクラスが常に 1 つの最大値である場合、なぜ順序が重要なのですか?

4

3 に答える 3

3

エラー メッセージが正しく報告するようTに、2 番目の呼び出しサイトでパラメーターに対して推論された型、つまりCheckable c = get()は単にであるため、エラーが発生します。Checkable

互換性のある型を使用するように呼び出しを強制すると、View & Checkableコンパイルされます。これを行うには、型を明示的に指定する必要があります。たとえば、次のようになります。

private <T extends View & Checkable> T get() {
   return (T) mView;
}

private <T extends View & Checkable> void useGeneric() {
    View v = this.get(); // no need for an explicit type
    Checkable c = this.<T>get(); // an explicit type needed
    T t = this.get(); // best way
}

private void useSpecific() {
    class Specific extends View implements Checkable {}
    Checkable c = this.<Specific>get(); // risk of ClassCastException
    Specific s = this.get(); // best way; risk of ClassCastException
}

クラスに割り当てる場合は明示的な型を必要としないが、インターフェイスの場合は明示的な型が必要であるという事実は、型推論アルゴリズムのアーティファクト、クラス/インターフェイスの非対称性のように見えます。

于 2016-08-24T14:06:29.743 に答える
0

問題は、アンパサンドの代わりにコンマがあることです! この定義:

private <T extends Checkable, View> T get() {

交差点ではありません!むしろ、クラスで使用されていない 2 つのジェネリック型 (1 つは named ともう 1 つは named ) を宣言TViewます。これはコーディングと同じです。

private <T extends Checkable, V> T get() {

したがって、次のように変更します。

private <T extends View & Checkable> T get() {

一般的な交差では、クラスはインターフェイスの前に来る必要があることに注意してください。

于 2013-10-30T09:26:29.613 に答える