有可能在Java中创建泛型类型的实例吗?我在想,根据我所看到的,答案是否定的(由于类型擦除),但如果有人能看到我遗漏的东西,我会很感兴趣:

class SomeContainer<E>
{
    E createContents()
    {
        return what???
    }
}

编辑:事实证明,超级类型令牌可以用来解决我的问题,但它需要大量基于反射的代码,如下面的一些答案所示。

我将把这个问题放一段时间,看看是否有人提出了与Ian Robertson的Artima文章截然不同的东西。


当前回答

如果你不想在实例化过程中键入类名两次,比如:

new SomeContainer<SomeType>(SomeType.class);

您可以使用工厂方法:

<E> SomeContainer<E> createContainer(Class<E> class); 

就像:

public class Container<E> {

    public static <E> Container<E> create(Class<E> c) {
        return new Container<E>(c);
    }

    Class<E> c;

    public Container(Class<E> c) {
        super();
        this.c = c;
    }

    public E createInstance()
            throws InstantiationException,
            IllegalAccessException {
        return c.newInstance();
    }

}

其他回答

这是我想到的一个选择,可能会有帮助:

public static class Container<E> {
    private Class<E> clazz;

    public Container(Class<E> clazz) {
        this.clazz = clazz;
    }

    public E createContents() throws Exception {
        return clazz.newInstance();
    }
}

EDIT:你也可以使用这个构造函数(但它需要一个E的实例):

@SuppressWarnings("unchecked")
public Container(E instance) {
    this.clazz = (Class<E>) instance.getClass();
}

注意,kotlin中的泛型类型可能没有默认构造函数。

 implementation("org.objenesis","objenesis", "3.2")

    val fooType = Foo::class.java
    var instance: T = try {
        fooType.newInstance()
    } catch (e: InstantiationException) {
//            Use Objenesis because the fooType class has not a default constructor
        val objenesis: Objenesis = ObjenesisStd()
        objenesis.newInstance(fooType)
    }

没有默认构造函数 Objenesis

不幸的是,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.newInstance();   // OK
    list.add(elem);
}

你可以像下面这样调用append方法:

List<String> ls = new ArrayList<>();
append(ls, String.class);

你可以用类加载器和类名,最终一些参数。

final ClassLoader classLoader = ...
final Class<?> aClass = classLoader.loadClass("java.lang.Integer");
final Constructor<?> constructor = aClass.getConstructor(int.class);
final Object o = constructor.newInstance(123);
System.out.println("o = " + o);

下面是一个createContents的实现,它使用TypeTools(我编写的)来解析由E表示的原始类:

E createContents() throws Exception {
  return TypeTools.resolveRawArgument(SomeContainer.class, getClass()).newInstance();
}

这种方法只适用于SomeContainer被子类化,所以E的实际值在类型定义中被捕获:

class SomeStringContainer extends SomeContainer<String>

否则E的值将在运行时被擦除,并且不可恢复。