6

この質問は、私の最後の質問に部分的に関連しています。

ジェネリック オブジェクトのコレクションを表すジェネリック クラスがあります。

public interface MyObject<N extends Number>{}

public interface MyCollecion<N extends Number> {
    public foo(MyObject<N> obj)
}

私の設計では、これらのオブジェクトのコレクションは、抽象クラス アプローチを通じてクライアント クラス (これを CollectionBuilder と呼びましょう) によって構築されます。

public interface AbstractCollectionFactory {
    public abstract <N extends Number> MyCollection<MyObject<N>> createCollection(String collectionType);

}

ジェネリック コレクションは、次のように構築する必要があります。

public class CollectionBuilder{
    AbstractCollectionFactory f;
    public void buildDoubleCollection(){

         MyCollection<MyObject<Double>> c = f.<Double>createCell("MyType");
    }
    public void buildIntegerCollection(){...}
}

わかりました。これで大丈夫です。CollectionBuilder は、指定する一般的な具象型 (この場合は Double) を認識しており、正しくビルドできます。これを警告なしでコンパイルでき、すべて正常に動作するはずです。

ここで、ジェネリックとプログラムの設計の両方に関連する質問があります。

CollectionBuilder によって構築されたコレクションを使用する必要があるアプリケーション内の別のクラスがあります (このクラスを UserClass と呼びましょう)。ユーザークラス:

  1. MyCollection<MyObject<Double>>特定の具象型がそのコレクション (または)であることを知る必要はありませんMyCollection<MyObject<Integer>>
  2. MyCollection インターフェイスで定義されたいくつかのメソッドを呼び出して、これらのコレクションに対していくつかの操作を実行します。
  3. ジェネリック型を追加したくありません。

説明されている状況では、UserClass 内のジェネリック クラス MyCollection をパラメータ化しないのは悪い考えですか?

public UserClass{
     MyCollection a;  //warning 
     MyCollection<?> b; //no warning

     public method(MyObject o){  //warning
          a.foo(b); //compile       
     }
     public method2(MyObject<?> o){
          b.foo(o); //error do not compile
     }
}

ジェネリック パラメータを指定しないと、Java コンパイラは常に警告を表示します。とにかく UserClass の内部からは、具体的なパラメーターがわからず (知りたくありません)、「?」で宣言することさえあります。MyCollection でメソッド foo を呼び出せないでください。

したがって、質問は次のとおりです。

  1. ジェネリック型への参照をパラメータ化しないことは常に悪いことですか?
  2. 1 の答えが NO の場合、それをしないのは正しい状況ですか?
  3. 1 の答えが YES の場合、ジェネリック型を知らなくても UserClass 内から MyCollection メソッドを使用するにはどうすればよいですか?
  4. 私のデザインは悪いですか?

明確になったことを願っています。私は何日もこの問題に苦労してきましたが、わかりません。私を助けてください。

4

4 に答える 4

6
  1. Java コンパイラによると、はい。そして、この答えには、その理由について多くの良い点が含まれています。個人的には、特に の使用Classが関係している場合 (たとえば、 がある場合Map<Class, Object>) には同意しません。そのような場合、常に<?>「クラス」の最後に追加する必要があるのは、不必要な退屈のように感じられ、コードを読みやすくしません。

    Class関連付けられているオブジェクトのタイプに基づいてパラメーター化するという考えは、最初は常に少し疑わしいと感じていました。そのポイントはClass、そのタイプに関係なく、任意のオブジェクトに関する情報を取得するために使用できる共通のインターフェイスを持つことです (ala リフレクション)。

    しかし、私は脱線します。Java コンパイラとジェネリック型の実装者によると、<?>.

  2. 適用できない。常に型情報を宣言することはできませんが@SuppressWarnings("unchecked")、明示的なキャストと一緒に使用してコンパイラを満足させることができます。

  3. ボヘミアンの答えを見てください。

  4. とは言え、本当に情報が足りない。思いつきではありますが、「ジェネリック オブジェクトのコレクションを表すジェネリック クラス」を実際に使用する場合がどうなるかはわかりません。コレクションを直接使用しないのはなぜですか?

于 2011-09-06T23:31:34.897 に答える
4

ほとんどの場合、コードをパラメーター化する方法があります。簡単に言うと、次のように UserClass と入力します。

public UserClass <N extends Number> {
     MyCollection<N> c;

     public method(MyObject<N> o){
          c.foo(o);      
     }
} 

編集
クライアントコードをジェネリックで汚染することが心配な場合は、次のように、抽象型付きクラスを作成し、型なし実装を提供できます。

public abstract UserClass <N extends Number> {
     MyCollection<N> c;

     public method(MyObject<N> o){
          c.foo(o);      
     }
} 

public class DoubleUserClass extends UserClass<Double> {}

クラスの肥大化を減らすために、型指定されていないクラスを基本クラス内に配置できます。

public abstract UserClass <N extends Number> {
     MyCollection<N> c;

     public method(MyObject<N> o){
          c.foo(o);      
     }

     public static class DoubleImpl extends UserClass<Double> {}
     public static class FloatImpl extends UserClass<Float> {}
     public static class IntegerImpl extends UserClass<Integer> {}
} 

そして、次のように使用します:new UserClass.DoubleImpl()など

于 2011-09-06T23:21:25.917 に答える
2

ジェネリックに夢中になるのは簡単です。どこかに立ち寄らなければなりません。いいえ、ジェネリック型への参照をパラメーター化しないことが常に悪いことだとは思いません。場合によっては、すべてのジェネリックを正確に正しく取得するために必要な余分な労力が、それだけの価値がない場合があります。

ただし、もちろん、可能であればジェネリックを指定する方がよいでしょう。あなたの例では、ボヘミアンが示唆するように、汎用パラメーターを UserClass に追加できます。

コレクションの設計が悪いかどうかについては、ここで定義しているインターフェイス/インフラストラクチャが一般的すぎるようです。MyCollection単純にできないことは何java.util.List<YourClass>ですか?MyObjectインターフェイスは本当に必要ですか?特定のタイプのクラスに「タグ付け」したい場合は、これらのオブジェクトが他のオブジェクトと何が違うのかについて、より具体的な説明を思い付くことができますObjectか?

于 2011-09-06T23:30:50.760 に答える