在Java中创建泛型类型的实例?

时间:2020-03-05 18:56:42  来源:igfitidea点击:

是否可以在Java中创建泛型类型的实例?我正在根据我所看到的答案进行思考,因为答案是"不"(由于类型擦除),但是如果有人能看到我所缺少的内容,我将很感兴趣:

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

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

我将对此开放一会儿,看看是否有人提出与Ian Robertson的Artima Article截然不同的东西。

解决方案

回答

如我们所说,由于类型擦除,我们无法真正做到这一点。我们可以使用反射来完成它,但是它需要大量代码和大量错误处理。

回答

你是对的。你不能做new E()。但我们可以将其更改为

private static class SomeContainer<E> {
    E createContents(Class<E> clazz) {
        return clazz.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();
    }
}

编辑:或者,我们可以使用此构造函数(但它需要E的实例):

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

回答

Dunno(如果有帮助),但是当我们继承(包括匿名)泛型类型时,可以通过反射获得类型信息。例如。,

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 );

但这是很多工作,并且仅适用于子类。虽然可以方便。

回答

我们将需要某种类型的某种抽象工厂,以将其责任传递给:

interface Factory<E> {
    E create();
}

class SomeContainer<E> {
    private final Factory<E> factory;
    SomeContainer(Factory<E> factory) {
        this.factory = factory;
    }
    E createContents() {
        return factory.create();
    }
}

回答

如果你的意思是
新E()
那是不可能的。我要补充一点,这并不总是正确的,我们怎么知道E是否具有公共的无参数构造函数?
但是我们总是可以将创建委托给其他知道如何创建实例的其他类,它可以是Class &lt;E>或者类似这样的自定义代码

interface Factory<E>{
    E create();
}    

class IntegerFactory implements Factory<Integer>{    
  private static int i = 0; 
  Integer create() {        
    return i++;    
  }
}

回答

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

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();
    }

}

回答

我们可以使用:

Class.forName(String).getConstructor(arguments types).newInstance(arguments)

但是我们需要提供确切的类名称,包括包。 java.io.FileInputStream。我用它来创建数学表达式解析器。

回答

package org.foo.com;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * Basically the same answer as noah's.
 */
public class Home<E>
{

    @SuppressWarnings ("unchecked")
    public Class<E> getTypeParameterClass()
    {
        Type type = getClass().getGenericSuperclass();
        ParameterizedType paramType = (ParameterizedType) type;
        return (Class<E>) paramType.getActualTypeArguments()[0];
    }

    private static class StringHome extends Home<String>
    {
    }

    private static class StringBuilderHome extends Home<StringBuilder>
    {
    }

    private static class StringBufferHome extends Home<StringBuffer>
    {
    }   

    /**
     * This prints "String", "StringBuilder" and "StringBuffer"
     */
    public static void main(String[] args) throws InstantiationException, IllegalAccessException
    {
        Object object0 = new StringHome().getTypeParameterClass().newInstance();
        Object object1 = new StringBuilderHome().getTypeParameterClass().newInstance();
        Object object2 = new StringBufferHome().getTypeParameterClass().newInstance();
        System.out.println(object0.getClass().getSimpleName());
        System.out.println(object1.getClass().getSimpleName());
        System.out.println(object2.getClass().getSimpleName());
    }

}