【问题标题】:Java: Instantiating a generic class with no default constructorJava:实例化一个没有默认构造函数的泛型类
【发布时间】:2012-09-15 00:19:05
【问题描述】:

我正在尝试这样做:

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 是相关的,但仅在假定类具有默认构造函数时才相关。

【问题讨论】:

    标签: java generics instantiation default-constructor


    【解决方案1】:

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

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

    在您的情况下,我更喜欢原型模式,因为您的 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());
    }
    

    【讨论】:

      【解决方案2】:

      不应该这样做的充分理由是,您不能强制子类实现某个构造函数。接口的实现很明显,因为它们不包含构造函数的合约。

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

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

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

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

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

      编辑

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

      【讨论】:

      • 和,T可以是抽象类或接口。在这种情况下,它在任何情况下都无法直接实例化。
      【解决方案3】:

      你需要使用工厂接口:

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


      附:这不是我原来的解决方案。我很久以前在某个地方找到了它,并在我的代码中使用了它。不幸的是,我找不到原始想法的链接...

      【讨论】:

        【解决方案4】:

        简单!

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

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

        实例化类型

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-02-23
          • 2017-10-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-04-09
          • 1970-01-01
          相关资源
          最近更新 更多