如何仅通过泛型类型T创建实例

时间:2017-07-27 12:28:47

标签: java generics

我想通过定义泛型类

的类型来创建实例
public abstract class Base<T> {
    private final T genericTypeObject;

    protected Base(){
          //Create instance of T here without any argument

    }
}

这样我就可以调用默认构造函数:

public class Child extends Base<SomeClass>{
    public Child () {
        super();
    }
}

并且Base-class实现将创建GenericType的实例。

3 个答案:

答案 0 :(得分:4)

通用信息将在编译时删除,因此在运行期间将不再有T (您放弃了信息)。这就是为什么你在某个地方需要Class<>来存储信息。

最干净的&amp;我的观点是简单的解决方案是将类传递给构造函数。我知道你要求它没有任何构造函数参数,但我不认为这是可能的。

代码示例

public abstract class AbstractBase<T> {

    private final T genericTypeObject;

    protected Base(Class<T> type){
        try {
            genericTypeObject = type.newInstance();
        } catch (InstantiationException e) {
            // Handle
        } catch (IllegalAccessException e) {
            // Handle
        }
    }
}
public class Child extends Base<SomeClass> {

    public Child () {
        super(SomeClass.class);
    }
}

替代解决方案

使用Supplier(感谢评论@Jorn Vernee):

public abstract class AbstractBase<T> {

  private final T genericTypeObject;

  public AbstractBase(Supplier<T> supplier) {
    genericTypeObject = supplier.get();
  }
}
public class Child extends AbstractBase<SomeClass> {

  public Child() {
    super(SomeClass::new);
  }
}

答案 1 :(得分:1)

在运行时,这会返回一个Class实例:

public static Class<?> getGenericClassOfType(Object object){
        Class<?> clazz = (Class<?>) ((ParameterizedType) object.getClass() .getGenericSuperclass()).getActualTypeArguments()[0];
        return clazz;
}

然后我可以用以下方式启动它:

public static <T> T getDefaultInstance(Class<T> clazz) throws IllegalAccessException, InvocationTargetException, InstantiationException {
    T instance = null;
    Constructor<T>[] constructors = (Constructor<T>[]) clazz.getDeclaredConstructors();
    Constructor<T> constructor = null;
    for (Constructor cstr : constructors) {
        //Only if default constructor
        if (cstr.getParameters().length == 0) {
            constructor = (Constructor<T>) cstr;
            break;
        }
    }
    if (constructor != null) {
        constructor.setAccessible(true);
        instance = constructor.newInstance();
    }

    return instance;
}

所以我的基础构造函数中的代码如下所示:

public abstract class BaseScene<T extends SceneController> {
    private final static Logger LOGGER =  LogManager.getLogger(BaseScene.class);

    private final T sceneController;

    //public T getSceneController() {
    //    return sceneController;
    //}

    protected BaseScene(){
        T newInstance = null;
        try {
            Class<T> clazz = (Class<T>)ReflectionHelper.getGenericClassOfType(this);
            newInstance = ReflectionHelper.getDefaultInstance(clazz);
        } catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
            LOGGER.error("Error while trying to initiate BaseScene",e);
        }
        sceneController = newInstance;
    }
}

在我测试时效果很好。

答案 2 :(得分:0)

您必须有权访问该类才能创建实例,因此无法创建不带参数的实例。您必须传递Class<T>

更新:

请参阅@JDC的答案。