【问题标题】:Calling constructor of a generic type调用泛型类型的构造函数
【发布时间】:2017-11-30 11:10:05
【问题描述】:

如果我有这样的抽象类:

public abstract class Item
{
    private Integer value;
    public Item()
    {
        value=new Integer(0);
    }
    public Item(Integer value)
    {
        this.value=new Integer();
    }
}

还有一些从 Item 派生的类,如下所示:

public class Pencil extends Item
{
    public Pencil()
    {
        super();
    }
    public Pencil(Integer value)
    {
        super(value);
    }
}

我不明白为什么我不能使用泛型调用构造函数:

public class Box <T extends Item>
{
    T item;
    public Box()
    {
        item=new T(); // here I get the error
    }
}

我知道可能有一个没有构造函数的类型,但这种情况是不可能的,因为 Pencil 的构造函数没有参数,而 Item 是抽象的。 但是我从 eclipse 中得到这个错误: 无法实例化类型 T
我不明白为什么,以及如何避免这种情况?

【问题讨论】:

标签: java generics


【解决方案1】:

这是因为 Java 使用擦除来实现泛型,请参见:

引用上述维基百科文章的相关部分:

在编译时检查泛型的类型正确性。然后在称为类型擦除的过程中删除泛型类型信息。

由于类型擦除,无法在运行时确定类型参数。

因此,实例化参数化类型的 Java 类是不可能的,因为实例化需要调用构造函数,如果类型未知,则该构造函数不可用。

您可以通过自己实际提供课程来解决这个问题。这在这里得到了很好的解释:

【讨论】:

  • 非常感谢。这个答案正是我正在寻找或说的:它完全符合我对 Java 通用实现的误解。 :-)
  • @MichaelDorner 当然可以,很高兴为您提供帮助!
【解决方案2】:

没有办法使用 Java 类型系统来强制类层次结构对其子类的构造函数具有统一的签名。

考虑:

public class ColorPencil extends Pencil
{
    private Color color;

    public ColorPencil(Color color)
    {
        super();
        this.color=color;
    }   
}

这使得 ColorPencil 成为一个有效的 T(它扩展了 Item)。但是,这种类型没有无参数构造函数。因此,T() 是无意义的。

要做你想做的事,你需要使用反射。您无法从编译时错误检查中受益。

【讨论】:

    【解决方案3】:

    您可以放置​​一个抽象方法,以便实现类可以确定如何构造新对象。

    public abstract T constructT();
    

    而不是调用

    T t = new T()
    

    你会打电话

    T t = constructT();
    

    在您的实施调用中,它将被创建为:

    new Box<Integer>() {
        public Integer constructT(){ return new Integer(); }
    }
    

    【讨论】:

      【解决方案4】:

      因为在运行时 T 的类型是未知的。

      【讨论】:

        【解决方案5】:

        T 是您的类将处理的实际类型的别名,例如,如果您实例化Box&lt;Item&gt;,那么T 实际上只是Item 的别名。当您声明T extends Item 时,您就知道T 至少具有与Item 相同的接口,因此您可以将其视为一个。

        我认为您真正想要做的不是实例化Box 中的item 字段,而是实现一些方法来让您操作该字段。

        public class Box<T extends Item> {
            private T item;
        
            public T getItem() {
                return this.item;
            }
        
            public void setItem(T item) {
                return this.item = item;
            }
        }
        

        【讨论】:

          【解决方案6】:

          使用 T 调用构造函数是不可能的,因为如果可以的话,编译后你会得到这样的代码:

          public class Box{
              Object item;
              public Box(){
                  item = new Object();
              }
          }
          

          因此,如果您使用此代码并传递一些对象,那么您会调用某些特定类型的构造函数,但您会得到 Object 构造函数。

          【讨论】:

          • 好吧,这只是不可能的,因为 Java 的泛型是如何实现的。
          猜你喜欢
          • 2017-03-12
          • 1970-01-01
          • 1970-01-01
          • 2019-09-19
          • 2021-08-17
          • 2010-10-16
          • 1970-01-01
          • 1970-01-01
          • 2019-02-20
          相关资源
          最近更新 更多