有可能在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).
我想我可以这样做,但很失望:它不起作用,但我认为它仍然值得分享。
也许有人可以纠正:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface SomeContainer<E> {
E createContents();
}
public class Main {
@SuppressWarnings("unchecked")
public static <E> SomeContainer<E> createSomeContainer() {
return (SomeContainer<E>) Proxy.newProxyInstance(Main.class.getClassLoader(),
new Class[]{ SomeContainer.class }, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Class<?> returnType = method.getReturnType();
return returnType.newInstance();
}
});
}
public static void main(String[] args) {
SomeContainer<String> container = createSomeContainer();
[*] System.out.println("String created: [" +container.createContents()+"]");
}
}
它产生:
Exception in thread "main" java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.String
at Main.main(Main.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
第26行带有[*]。
唯一可行的解决方案是@JustinRudd的方案
我不知道这是否有帮助,但当您子类化(包括匿名)泛型类型时,类型信息可以通过反射获得。例如,
public abstract class Foo<E> {
public E instance;
public Foo() throws Exception {
instance = ((Class)((ParameterizedType)this.getClass().
getGenericSuperclass()).getActualTypeArguments()[0]).newInstance();
...
}
}
所以,当你子类化Foo时,你得到Bar的一个实例,例如,
// notice that this in anonymous subclass of Foo
assert( new Foo<Bar>() {}.instance instanceof Bar );
但是工作量很大,而且只适用于子类。不过也很方便。