Java:实例化没有默认构造函数的泛型类

时间:2010-01-21 04:12:19

标签: java generics instantiation default-constructor

我正在尝试这样做:

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参数。

如何做到这一点?


我也在这里问follow up question。如果你能回答这个问题,我将不胜感激。

question是相关的,但仅在假定类具有默认构造函数的情况下才相关。

4 个答案:

答案 0 :(得分:5)

已经说过,你不能用new创建T的实例,所以 我会使用工厂模式或原型模式

所以你的构造函数看起来像 public BaseTable(int rows, int cols, LineFactory factory)具有适当的工厂实例。

在你的情况下,我更喜欢Prototype Pattern,因为你的TableEntry对象可能非常轻量级。您的代码如下:

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());
}

答案 1 :(得分:3)

不应该这样做的好理由是,你不能强迫子类实现某个构造函数。对于接口的实现来说非常明显,因为它们不包含构造函数的契约。

如果你的真实或抽象类BaseTable有一个构造函数BaseTable(int columns),那么带有单个列的虚构子类VectorTable就不需要实现它,并且可以做一些像

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

首先,你不知道T是否实现了构造函数,其次,你不知道构造函数是否具有相同的目的(它应该在正确的代码中真正具有它! !

所以我认为,更好的解决方案是将参数化部分从构造函数移动到单独的(final?)方法中,使用默认构造函数创建实例并在之后调用该初始化方法。

如果您想确保所有BaseTable子类始终都能正确初始化,您可以考虑实现BaseTableFactory

修改

并且new T()(实例化默认构造函数)也是不可能的,因为没有类可以强制来实现可访问的默认构造函数。我仍然认为,工厂模式是你最好的朋友。

答案 2 :(得分: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);


P.S。这不是我原来的解决方案。我很久以前就找到了它并在我的代码中使用它。不幸的是,我找不到原创想法的链接......

答案 3 :(得分:-1)

简单!

使用静态工厂方法而不是构造函数:

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

实例化类型

BaseTable<Number> = BaseTable.newInstance(10, 20);