我用这样的通用返回类型调用一个方法:
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;
}
有没有办法在此方法中创建实例而不将Class
作为方法参数? (Class<T> c
)
答案 0 :(得分:3)
不,不幸的是,没有。这是首先必须通过Class<T>
的主要原因。
Java编译器在称为 type erasure 的过程中从已编译的类和方法中剥离通用信息。编译器完成时,所有T
成为Object
s或下限类型(这将对应于示例中的HotelBean
)。如果无法访问Class<T>
,则该方法无法恢复类型参数,这是生成新实例所必需的。
请注意,您的示例必须以这种方式或其他方式传递所需的类型,因为您使用可能是HotelBean
的子类的对象填充基类对象的列表。
答案 1 :(得分:1)
而不是传递Class
来创建一个实例,这意味着必须处理捕获或抛出异常,而不是传递Supplier<T>
。
java.util.function.Supplier<T>
(Java 8特性)是一个功能接口,它有一个方法get
,它返回一个T
类型的对象。
使用Supplier<T>
看起来像这样:
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;
}
您可以传递不带参数的方法引用并返回类型为T
的对象作为供应商,其中包含T
的默认构造函数。
class MyClass {
public MyClass() {...}
}
fill(MyClass::new);
与newInstance()
的主要区别在于,Supplier<T>
返回的对象不一定是 new 对象,因为您不必通过{{ 1}}。您可以传递任何不带参数的方法并返回MyClass::new
。