4

私はこれをやろうとしています:

public class BaseTable<T extends TableEntry>

{

    protected int mRows;
    protected int mCols;
    protected ArrayList<T> mEntries;

    public BaseTable(int rows, int cols)
    {
        mRows = rows;
        mCols = cols;
        mEntries = new ArrayList<T>();
        for (int i = 0; i < rows; i++)
        {
            mEntries.add(new T(cols)); //this obv. doesn't work
        }
    }
}

ジェネリックスのインスタンス化はそれなりに難しいですが、これをさらに難しくしているのは、Tここにはデフォルトのコンストラクターがなく、コンストラクターで単一のintパラメーターを使用することです。

これはどのように行うことができますか?


ここでもフォローアップの質問をしました。それにもお答えいただければ幸いです。

この質問は関連していますが、クラスにデフォルトのコンストラクターがあると想定される場合にのみ関連します。

4

4 に答える 4

5

で T のインスタンスを作成できないことは既に述べたnewので、Factory パターンまたは Prototype パターンを使用します。

したがって、コンストラクターは public BaseTable(int rows, int cols, LineFactory factory)、ファクトリの適切なインスタンスのようになります。

あなたの場合、 TableEntry オブジェクトはおそらく非常に軽量であるため、Prototype パターンを好みます。コードは次のようになります。

public BaseTable(int rows, int cols, T prototype)
{       
  mRows = rows;
  mCols = cols;
  prototype.setColumns(cols);
  mEntries = new ArrayList<T>();
  for (int i = 0; i < rows; i++)
  {
    @SuppressWarnings("unchecked")
    T newClone = (T)prototype.clone();
    mEntries.add(newClone); //this obv. does work :)
  }
}

public static void main(String[] args)
{
  new BaseTable<SimpleTableEntry>(10, 2, new SimpleTableEntry());
}
于 2010-01-21T11:26:22.597 に答える
3

このようにすべきではない正当な理由は、サブクラスに特定のコンストラクターを強制的に実装することはできないからです。インターフェイスの実装では、コンストラクターのコントラクトが含まれていないため、これは非常に明白です。

そして、実際のクラスまたは抽象クラスBaseTableにコンストラクターがある場合、単一の列を持つBaseTable(int columns)架空のサブクラスVectorTableはそれを実装する必要がなく、次のような悪いことをする可能性があります

public VectorTable(int intialValue) {
  super(1);
  this.initialValue = initialValue;
}

したがって、最初にT、コンストラクターをまったく実装しているかどうかがわかりません。次に、コンストラクターが同じ目的を持っているかどうかがわかりません (これは、適切なコードで実際に持つ必要があります!! ) 。

したがって、より良い解決策は、パラメーター化された部分をコンストラクターから別の (最終的な?) メソッドに移動し、デフォルトのコンストラクターでインスタンスを作成し、その後すぐにその初期化メソッドを呼び出すことです。

BaseTableFactoryすべての BaseTable サブクラスが常に正しく初期化されることを確認したい場合は、 を実装することを考えるかもしれません。

編集

また、 (既定のコンストラクターをインスタンス化する) こともできません。これは、アクセス可能な既定のコンストラクターを強制的に実装するnew T()クラスがないためです。私は今でも、工場パターンがここでのあなたの親友だと思います.

于 2010-01-21T07:22:23.813 に答える
1

Factory インターフェイスを使用する必要があります。

public interface TableEntryFactory<T extends TableEntry>{
 public T create (int cols);
}

また、「タイプT」の各クラスのファクトリを作成する必要があります。

// for every class of type T
public class SpecialTableEntry extends TableEntry{
   SpecialTableEntry(int cols){
      ...
   }
}

// make a factory creating instance of this class
public class SpecialTableEntryFactory implements TableEntryFactory<SpecialTableEntry> {
   @Override
   public SpecialTableEntry create (int cols){
       return new SpecialTableEntry(cols);
   }
}

コードは次のようになります。

public class BaseTable<T extends TableEntry>

{

protected int mRows;
protected int mCols;
protected ArrayList<T> mEntries;

public BaseTable(int rows, int cols, TableEntryFactory<T> tableFactory)
{
    mRows = rows;
    mCols = cols;
    mEntries = new ArrayList<T>();
    for (int i = 0; i < rows; i++)
      {
        mEntries.add(tableFactory.create(cols)); //this should work now
      }
  }
}


次のように呼び出すことができます。

TableEntryFactory<SpecificTableEntry> myFactory = new SpecificTableEntryFactory();
BaseTable<?> table = new BaseTable<SpecificTableEntry>(rows,cols,myFactory);


PSそれは私の元の解決策ではありません。ずっと前にどこかで見つけて、コードで使用しました。残念ながら、元のアイデアへのリンクが見つかりません...

于 2012-09-14T16:19:05.647 に答える
-1

単純!

コンストラクターの代わりに静的ファクトリメソッドを使用します。

public static <T extends TableEntry> newInstance(int rows, int cols) {
    return new BaseTable<T>(rows, cols);
}

タイプをインスタンス化するには

BaseTable<Number> = BaseTable.newInstance(10, 20);
于 2010-01-21T23:20:55.997 に答える