0

私はトランプのデッキを表すクラスを作ろうとしてきました。でも、どんなカードでもいいように作りたかったので、どの種類のカードを収納して、シャッフルして、一度に1枚ずつ引くことができるのかを知る必要はありません。通常のトランプ、またはトレーディングカード。このために、私は聞いたことはあるが使用したことのないもの、つまりジェネリックを試してきました。

しかし、私はそれを機能させることを試みてまったく運がありませんでした。カードを引くときに、インスタンス化したり、カードにデータを入力したり、正しいタイプを返したりすることはありません。ミキシングとマッチングを試しましたが、うまく機能しません。

バグのある古いコードはスペースを節約するために切り捨てられました。以前の編集を見てください。要約:私はTの代わりにCardableを使用し、一般的にジェネリックを表現することができませんでした。

それで、これはどのように機能するのでしょうか、私はジェネリックに完全に慣れていません。私はいたるところを見回していて、型消去について聞き続けています。クラスリテラルはパラメータであり、yadda yaddaである必要があります...しかし、ArrayListはどのようにそれを行うのでしょうか。ArrayList<String>()入力するだけで、ばかげたようなものを必要とせずに機能するのはなぜArrayList<String>(String.GetClass())ですか?

御時間ありがとうございます。

編集:Cardableは、デッキに入れることができるすべてのカードが拡張されるクラスです。

Edit2:Perceptionの提案によりコードは修正されましたが、デッキにデータを入力するためにどのように呼び出すことができるかわかりません。現在、配列を受け入れることができますが、内部にあると便利であり、ファクトリメソッド全体を把握できるかどうかは完全にはわかりません。

public class Deck<T extends Cardable>
{
    private ArrayList<T> cardsInDeck;

    public Deck()
    {
        cardsInDeck = new ArrayList<T>();
    }

    public void populate( T[] newCards )
    {
        cardsInDeck.clear();
        for( T card : newCards )
        {
            cardsInDeck.add( card );
        }
        shuffle();
    }

    public T drawCard()
    {
        T card = null;
        try
        {
            card = cardsInDeck.get( 0 );
        }
        catch( IndexOutOfBoundsException e )
        {
            System.out.println( "Ran out of Cards" );
            e.printStackTrace();
        }
        cardsInDeck.remove( 0 );
        return card;
    }

    public void shuffle()
    {
        ArrayList<T> newDeck = new ArrayList<T>();
        Random rand = new Random();
        while( !cardsInDeck.isEmpty() )
        {
            int index = rand.nextInt( cardsInDeck.size() );
            newDeck.add( cardsInDeck.get( index ) );
            cardsInDeck.remove( index );
        }
        cardsInDeck = newDeck;
    }

    public int getSize()
    {
        return cardsInDeck.size();
    }
}
4

4 に答える 4

2

重要なのは、の実装はArrayList<E>実際の型Eに依存しないということです。そのため、コンストラクターで型を渡す必要はありません(あなたが言うようにnew ArrayList<String>(String.class))。

何らかの理由で、実行時にジェネリック型が何を表すかを正確に知る必要があるジェネリッククラスを作成する場合は、型消去ではクラスを取得できないため、コンストラクターで型を渡す必要があります。からT。あなたが必要だろうnew MyClassThatNeedToKnowItsActualTypeParameter<String>(String.class)

たとえば、データベースにアクセスし、特定のクラスのインスタンスを取得するクラスがあるとします。クラスのインスタンスは、クラスにちなんで名付けられたテーブルに格納されます。例えば:

class MyRepository<T> {
  T load(int id) { ... }
}

このメソッドloadは、Tが表す実際のクラスの名前を使用するクエリを作成できる必要があるため、実行時にTが何であるかを正確に知る必要があります。ただし、Javaでは、型消去により表示されなくなるためT、からこの情報を取得することはできません。Tさらに、このloadメソッドには、正しいタイプのインスタンスを作成し、データベースからそのインスタンスにデータを書き込む方法が必要です。クラスのインスタンスを作成するには、たとえばリフレクションを使用しますclazz.newInstance()。ここでも、どのクラスを扱っているかを正確に知る必要があります。あなたはこのようなものになってしまうでしょう:

class MyRepository<T> 
  private final Class<T> clazz;
  MyRepository(Class<T> clazz) { this.clazz = clazz; }
  T load(int id) {
    final String tableName = clazz.getSimpleName() + "Table";
    /* connect, retrieve data, disconnect */
    final T t = clazz.newInstance(); // must be inside try/catch
    /* fill instance t with data from database somehow (using reflection probably, which, again, needs to know what clazz is */
    return t;
  }
}

...
final MyRepository<User> userRepository = new MyRepository<User>(User.class);
final User user = userRepository.load(123);
...
于 2013-01-13T06:16:16.717 に答える
1

これにはジェネリックスを使用できますが、デッキはそれ自体を取り込むことができません。作成するオブジェクトのクラスがわかりません。あなたの説明から、あなたが望むのは基本的にArrayList<T>どこTにでもあることができるということです。カードである必要はありません。ただし、必要なのはデッキを埋める方法です。そのために、ファクトリオブジェクトを使用できます。

public interface CardGenerator<T> {
    T[] generateAllCards();
}

public class Deck<T> {
    private ArrayList<T> cardsInDeck;

    public Deck(CardGenerator<T> generator) {
        cardsInDeck = new ArrayList<T>();
        cardsInDeck.addAll(generator.generateAllCards());
    }
    . . .
}

T必要に応じて、拡張するタイプを制限できますがCardable、のロジックに関してはDeck(説明した限り)、それは必要ありません。

于 2013-01-13T06:17:14.513 に答える
0

コードを見ると、Tをほとんど使用していないため、ジェネリッククラスが本当に必要だとは思いません。populateメソッドを次のようなものに変更するだけの場合は、次のようにする必要があります。

public void populate(Cardable t)
    {
        cardsInDeck.clear();
        Cardable[] cardsMade;

        cardsMade = t.makeAllCards();

        for( Cardable card : cardsMade )
        {
            cardsInDeck.add( card );
        }


        shuffle();
    }
于 2013-01-13T06:18:37.480 に答える
0

ジェネリックを使用しないでください。

さまざまな種類のカードを処理したい場合にのみ、遺伝学を使用します。

  • 52カードデッキ
  • タロットカード
  • 63カード5ハンド500デッキ

この問題はあなたの状況には当てはまりません。

于 2013-01-13T07:35:46.140 に答える