Java 在方法内创建泛型实例

Java 在方法内创建泛型实例,java,generics,methods,Java,Generics,Methods,我调用了一个具有如下一般返回类型的方法: public static <T extends HotelBean> List<T> fill(Class<T> c) throws InstantiationException, IllegalAccessException { List<T> list = new ArrayList<>(); for (int i = 0; i <= 2; i++) {

我调用了一个具有如下一般返回类型的方法:

public static <T extends HotelBean> List<T> fill(Class<T> c) throws InstantiationException, IllegalAccessException {
    List<T> list = new ArrayList<>();
    for (int i = 0; i <= 2; i++) {
        T t = c.newInstance();
        list.add(t);
    }
    return list;
}
public static <T extends HotelBean> List<T> fill(Supplier<T> supp) { // No more exceptions!
    List<T> list = new ArrayList<>();
    for (int i = 0; i <= 2; i++) {
        T t = supp.get();
        list.add(t);
    }
    return list;
}

有没有一种方法可以在这个方法中创建一个实例而不将类作为方法参数?c类

不,不幸的是,没有。这是首先必须通过考试的主要原因

Java编译器在称为类型擦除的过程中从编译的类和方法中剥离通用信息。当编译器完成时,所有的T都成为对象或下限类型,这将对应于示例中的HotelBean。如果没有对类的访问权,该方法将无法恢复类型参数,这是生成新实例所必需的


请注意,您的示例必须以这种或那种方式传递所需的类型,因为您正在用可能是HotelBean子类的对象填充基类对象列表。

不,不幸的是,没有。这是首先必须通过考试的主要原因

Java编译器在称为类型擦除的过程中从编译的类和方法中剥离通用信息。当编译器完成时,所有的T都成为对象或下限类型,这将对应于示例中的HotelBean。如果没有对类的访问权,该方法将无法恢复类型参数,这是生成新实例所必需的

请注意,您的示例必须以这种或那种方式传递所需的类型,因为您正在用可能是HotelBean子类的对象填充基类对象列表。

而不是传递要创建实例的类,这意味着必须处理捕获或引发异常的问题,你可以通过一个供应商代替

,一个Java8特性,是一个函数接口,它有一个方法get,返回一个类型为T的对象

使用供应商将如下所示:

public static <T extends HotelBean> List<T> fill(Class<T> c) throws InstantiationException, IllegalAccessException {
    List<T> list = new ArrayList<>();
    for (int i = 0; i <= 2; i++) {
        T t = c.newInstance();
        list.add(t);
    }
    return list;
}
public static <T extends HotelBean> List<T> fill(Supplier<T> supp) { // No more exceptions!
    List<T> list = new ArrayList<>();
    for (int i = 0; i <= 2; i++) {
        T t = supp.get();
        list.add(t);
    }
    return list;
}
newInstance的主要区别在于,从供应商返回的对象不一定是新对象,因为您不必传递MyClass::new。您可以传递任何不带参数并返回T的方法。

而不是传递用于创建实例的类,这意味着必须处理捕获或抛出异常的问题,您可以传递供应商

,一个Java8特性,是一个函数接口,它有一个方法get,返回一个类型为T的对象

使用供应商将如下所示:

public static <T extends HotelBean> List<T> fill(Class<T> c) throws InstantiationException, IllegalAccessException {
    List<T> list = new ArrayList<>();
    for (int i = 0; i <= 2; i++) {
        T t = c.newInstance();
        list.add(t);
    }
    return list;
}
public static <T extends HotelBean> List<T> fill(Supplier<T> supp) { // No more exceptions!
    List<T> list = new ArrayList<>();
    for (int i = 0; i <= 2; i++) {
        T t = supp.get();
        list.add(t);
    }
    return list;
}

newInstance的主要区别在于,从供应商返回的对象不一定是新对象,因为您不必传递MyClass::new。您可以传递任何不带参数并返回T的方法。

由于类型擦除,这种方法中可能没有。编译器也无法推断T的实际类型。删除该参数的唯一方法是在某些反射数据中定义T的类型,即字段定义或具有具体类型的类。然而,这可能会与方法的目的相矛盾,或者至少比传递参数不容易。不,泛型类型会被删除,所以Java在运行时可以用来确定其应创建的实例类型的唯一东西来自类。您也可以传递供应商,使用MyType::new方法引用作为参数。那至少可以摆脱这些抛投clause@JornVernee你能提供一个使用供应商的例子吗?我对你的解决方案很感兴趣。@Patrick我会回答,由于类型擦除的原因,可能不会使用这种方法。编译器也无法推断T的实际类型。删除该参数的唯一方法是在某些反射数据中定义T的类型,即字段定义或具有具体类型的类。然而,这可能会与方法的目的相矛盾,或者至少比传递参数不容易。不,泛型类型会被删除,所以Java在运行时可以用来确定其应创建的实例类型的唯一东西来自类。您也可以传递供应商,使用MyType::new方法引用作为参数。那至少可以摆脱这些抛投clause@JornVernee你能提供一个使用供应商的例子吗?我对你的解决方案很感兴趣。@Patrick我会回答的谢谢你的回答。有更好的实现方法吗?或者我应该继续使用这种方法吗?即使没有类型擦除,编译器也无法推断T的类型,因此您必须使用HotelBean,这将使泛型成为超级函数,或者告诉方法,例如,通过像这样调用它。fill-这似乎并不比fill更可取SpecialHotelBean.class.@Patrick我不会尝试发明一种不同的方法,因为您拥有的是构建对象创建通用代码的惯用解决方案。其他程序员阅读您的代码时,会立即识别它,并理解您的代码
“我正在努力。”托马斯:这很有道理,谢谢你的评论。虽然在某些情况下编译器可以推断类型,例如,当您分配给List或调用使用List参数的方法时,必须提供精确的类型才能使方法工作。是的,这些情况都是由于类型擦除而中断的。谢谢您的回答。有更好的实现方法吗?或者我应该继续使用这种方法吗?即使没有类型擦除,编译器也无法推断T的类型,因此您必须使用HotelBean,这将使泛型成为超级函数,或者告诉方法,例如,通过像这样调用它。fill-这似乎并不比fill更可取SpecialHotelBean.class.@Patrick我不会尝试发明一种不同的方法,因为您拥有的是构建对象创建通用代码的惯用解决方案。其他程序员阅读您的代码时会立即识别它,并理解您正在尝试做什么。@Thomas这很有意义,谢谢您的评论。虽然有些情况下编译器可以推断类型,例如,当您分配给List或调用一个使用List参数的方法时,必须提供精确的类型才能使该方法工作。是的,这些情况是由于类型擦除而中断的。