有可能在Java中创建泛型类型的实例吗?我在想,根据我所看到的,答案是否定的(由于类型擦除),但如果有人能看到我遗漏的东西,我会很感兴趣:
class SomeContainer<E>
{
E createContents()
{
return what???
}
}
编辑:事实证明,超级类型令牌可以用来解决我的问题,但它需要大量基于反射的代码,如下面的一些答案所示。
我将把这个问题放一段时间,看看是否有人提出了与Ian Robertson的Artima文章截然不同的东西。
如果你在泛型类中需要一个类型参数的新实例,那么让你的构造函数要求它的类…
public final class Foo<T> {
private Class<T> typeArgumentClass;
public Foo(Class<T> typeArgumentClass) {
this.typeArgumentClass = typeArgumentClass;
}
public void doSomethingThatRequiresNewT() throws Exception {
T myNewT = typeArgumentClass.newInstance();
...
}
}
用法:
Foo<Bar> barFoo = new Foo<Bar>(Bar.class);
Foo<Etc> etcFoo = new Foo<Etc>(Etc.class);
优点:
比Robertson的超级类型令牌(STT)方法简单得多(而且问题更少)。
比STT方法更有效(STT方法会把你的手机当早餐吃)。
缺点:
Can't pass Class to a default constructor (which is why Foo is final). If you really do need a default constructor you can always add a setter method but then you must remember to give her a call later.
Robertson's objection... More Bars than a black sheep (although specifying the type argument class one more time won't exactly kill you). And contrary to Robertson's claims this does not violate the DRY principal anyway because the compiler will ensure type correctness.
Not entirely Foo<L>proof. For starters... newInstance() will throw a wobbler if the type argument class does not have a default constructor. This does apply to all known solutions though anyway.
Lacks the total encapsulation of the STT approach. Not a big deal though (considering the outrageous performance overhead of STT).
对诺亚的回答进行了改进。
改变的原因
a]如果使用多于一个泛型类型,则更安全,以防您更改顺序。
b]类泛型类型签名会不时变化,这样你就不会对运行时中无法解释的异常感到惊讶。
健壮的代码
public abstract class Clazz<P extends Params, M extends Model> {
protected M model;
protected void createModel() {
Type[] typeArguments = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
for (Type type : typeArguments) {
if ((type instanceof Class) && (Model.class.isAssignableFrom((Class) type))) {
try {
model = ((Class<M>) type).newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
}
或者使用一个眼线笔
一行代码
model = ((Class<M>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]).newInstance();
摘自Java教程-泛型的限制:
不能创建类型参数的实例
不能创建类型参数的实例。例如,下面的代码会导致编译时错误:
public static <E> void append(List<E> list) {
E elem = new E(); // compile-time error
list.add(elem);
}
作为一种变通方法,你可以通过反射创建一个类型参数的对象:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.getDeclaredConstructor().newInstance(); // OK
list.add(elem);
}
你可以像下面这样调用append方法:
List<String> ls = new ArrayList<>();
append(ls, String.class);