3

解決する次のシナリオ: 特定の id+classtype に応じて、果物のリストを返すか保存するクラスを作成する必要があります。だから私は自分自身に疑問を呈していCollectionましCollectionた。キーと値の原則は私のユースケースによく似ているため、すべてのリストを保存するために単一HashMapの試みを行うことにしました。2 つの側面 (私の場合は id と果物クラス)、値を識別します。

そこで、独自のキー オブジェクトを作成しました。

class FruitKey
{
  int                     id;
  Class<? extends Fruits> type;

  public FruitKey( int id, Class<? extends Fruits> type )
  {
    this.id = id;
    this.type = type;
  }

  //equals, hashcode, etc.
}

を作成した後Map<FruitKey, List<? extends Fruits>>、 put は完全に正常に機能しますが、もちろん、FruitLists を Map から取得しようとすると、特定の果物の種類を保証できず、結果をキャストする必要があります。

public static void main( String[] args )
{
  Map<FruitKey, List<? extends Fruits>> fruitMap = new HashMap<>();

  Apple oneApple = new Apple();
  List<Apple> manyApples = new ArrayList<>();
  manyApples.add( oneApple );

  fruitMap.put( new FruitKey( 1, Apple.class ), manyApples);

  //Any way to avoid typesafty and cast?
  List<Apple> myApples = (List<Apple>) fruitMap.get( new FruitKey( 1, Apple.class ) );
}

classtype はすでにキーに含まれているので、これらをマップの値に関連付けることができると思ったのですが、残念ながらマップを特別な果物専用にすることなく、成功しませんでした。タイプセーフ/クラスキャストの問題を回避する可能性はありますか、それとも私の目的を達成するために別のコレクションタイプを推奨できますか? もちろん、果物ごとにマップを作成することもできますが、おいしい果物がたくさんあるので、それらを常に区別する必要があるため、それを避けようとしました.

要するに、これは私が欲しいものです:

List<Apple> apples = SomeCollection.get( Key(id, Apple.class) );

Id も存在する理由は、同じマップ内に複数のリンゴのリストと、他の果物の複数のリストが存在する可能性があるためです。

4

1 に答える 1

1

異種コンテナーを使用できます。コンテナー内でキャストする必要がありますが、ジェネリック メソッドとfinalクラスの により、キャストは安全であり、警告を抑制することができます。

ジェネリックputにより、キャストに失敗するようなものを決して入れられないことが保証されるため、安全です。

public final class SomeCollection {

     private Map<FruitKey<? extends Fruits>, List<? extends Fruits>> fruitMap = new HashMap<>();

     //safe cast
     @SuppressWarnings("unchecked")
     public <T extends Fruits> List<T> get(FruitKey<T> key)
     {
         return (List<T>) fruitMap.get(key);
     }

     public <T extends Fruits> void put(FruitKey<T> key, List<T> fruits)
     {
         fruitMap.put(key, fruits);
     }
}

タイプされたFruitKey

class FruitKey<T extends Fruits>
{
   int                     id;
   Class<T> type;

   public FruitKey( int id, Class<T> type )
   {
      this.id = id;
      this.type = type;
   }     
}

編集

バスケットの と適切なをカプセル化する 内にKey<T>内部クラスを作成することもできます。SomeCollectionFruitKeyhashCodeequals

private Map<Key<? extends Fruits>, List<? extends Fruits>> fruitMap = new HashMap<>();

//safe cast
@SuppressWarnings("unchecked")
public <T extends Fruits> List<T> getBasket(T fruit)
{
    Key<T extends Fruit> = new Key<T>(fruit.getBasketId());
    return (List<T>) fruitMap.get(key);
}
//or
//safe cast
@SuppressWarnings("unchecked")
public <T extends Fruits> List<T> getBasket(Class<T> klass, FruitKey key)
{
    Key<T extends Fruit> = new Key<T>(key);
    return (List<T>) fruitMap.get(key);
}

public <T extends Fruits> void addToBasket(T fruit, List<T> fruits)
{
    Key<T extends Fruit> = new Key<T>(fruit.getBasketId());
    fruitMap.put(key, fruits);
}
于 2012-11-09T12:16:02.757 に答える