【问题标题】:How to create new object of Generic Type T from a parametrized List<T>如何从参数化 List<T> 创建通用类型 T 的新对象
【发布时间】:2018-04-20 10:34:28
【问题描述】:

我有以下 java 示例类:

public class TestClass {

    public static <T> void method(List<T> objects) throws Exception {
        for (int i = 0; i < objects.size(); i++) {
            // Create new object of the same class
            T obj = (T) objects.get(i).getClass().newInstance();
        }
    }
}

它正在产生编译器警告:

类型安全:来自 capture#1-of 的未经检查的强制转换?将对象扩展到 T

如果我这样做,我可以完美地获得确切的 T 对象:

T obj = objects.get(i);

它完全知道的是T型。

为什么我无法创建该类的新实例?我该如何解决?

(我不是在寻找以下类型的响应:'Add @SuppressWarnings("unchecked")')

【问题讨论】:

标签: java generics


【解决方案1】:

这是因为getClass() 返回了Class&lt;? extends Object&gt;。您不能(安全地)将通配符 ? 转换为任何东西,甚至不能转换为泛型类类型。这是 Java 泛型的限制。但既然您可以确定此警告不是问题,您可以放心地忽略或取消它。


但这里有一个解决方法,许多应用程序和库都这样做:

public static <T> void method(List<T> objects, Class<T> clazz) throws Exception {
    for (int i = 0; i < objects.size(); i++) {
        // Create new object of the same class
        T obj = clazz.newInstance();
    }
}

【讨论】:

    【解决方案2】:

    泛型在运行时被删除。因此,在列表的已声明 T 元素上调用 getClass() 会返回一个 &lt;? extends Object&gt; 类实例。

    Object.getClass() 确实表示:

    实际结果类型是Class&lt;? extends |X|&gt;,其中|X| 是 擦除 getClass 所在的表达式的静态类型 叫。

    要调用newInstance() 并创建T 的实例,您需要知道要实例化的Class 实例,但请注意List 可以包含T 的任何子类,因此传递一个类作为参数可能还不够。

    例如:

    List<Animal> list = new ArrayList<>();
    list.add(new Lion());
    list.add(new Rabbit());
    list.add(new Turtle());
    

    现在调用了哪一个?

    method(list, Lion.class); 
    method(list, Rabbit.class);
    method(list, Turtle.class);
    

    没有人会编译!所以这显然是不够的。
    所以我认为通过抑制警告来保留原始代码更有意义。通过这种方式,您可以确保创建与列表中的实际元素相同的类的实例:

    public static <T> void method(List<T> objects) throws Exception {
        for (int i = 0; i < objects.size(); i++) {
            // Create new object of the same class
            @SuppressWarnings("unchecked")
            T obj = (T) objects.get(i).getClass().newInstance();
            System.out.println(obj);
        }
    }
    

    【讨论】:

      【解决方案3】:

      为什么我无法创建该类的新实例?

      你是。您的代码将编译并按预期工作,但编译器不能 100% 确定这一点,因为类型擦除这就是您收到警告的原因。这里需要注意的重要一点是警告与错误不同。

      (我不是在寻找以下类型的响应:'Add @SuppressWarnings("unchecked")')

      如果您查看任何将泛型和反射结合使用的 Java 代码库,您将看到针对类型安全的抑制警告。不幸的是,这只是生活中的事实。

      【讨论】:

      • 我认为真正的问题是他为什么需要投。该方法将Class&lt;T&gt; 的返回类型声明为T。所以有人会假设它返回T 而不是Object
      • @Zabuza 但objects.get(i).getClass() 不返回Class&lt;T&gt;
      • @Kayaman 我知道,但我认为这是人们会假设的。因此,OP 提出了这个问题。
      猜你喜欢
      • 1970-01-01
      • 2019-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-01
      • 2019-05-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多