【问题标题】:How to create an instance just by generic type T [duplicate]如何仅通过泛型类型 T 创建实例 [重复]
【发布时间】:2017-07-27 12:28:46
【问题描述】:

我想通过定义泛型类的类型来创建一个实例

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 的实例。

【问题讨论】:

  • 你可能会问XY Problem,所以你最好解释一下你的整体问题,而不是你试图(错误地)解决它的方式。
  • 您想要一个“干净”的解决方案,还是对肮脏的、基于反射的 hack 感到满意?我曾经试图做类似的事情,我已经放弃了,但最近我想我已经想通了——虽然它真的很老套。如果这适合你,我可以尝试最终做到这一点。
  • 也许你可以同时提供给我 :D 我让其他人的问题很简单。之后我会决定哪个最适合:D
  • 这是肮脏的答案: Class s; public Child(Class s) { this.s = s; } 私有 T getInstance() { 返回 s.newInstance(); }
  • “没有任何参数” 为什么你有这个要求?将T 的实例传递给超级构造函数是迄今为止我能想到的最干净的解决方案。

标签: java generics


【解决方案1】:

通用信息将在编译时删除,因此在运行时将不再有T(您丢失了信息)。这就是为什么您在某个地方需要Class&lt;&gt; 来存储信息的原因。


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


代码示例

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

【讨论】:

  • 我建议传递一个构造函数reference,而不是这个,因为它不会抛出任何异常。
  • 谢谢,添加了您的建议。
  • 在我没有类的情况下,擦除部分可能是正确的,泛型类型是从某些东西扩展而来的。也许我的问题是简化。
【解决方案2】:

您必须有权访问该类才能创建实例,因此无法创建没有参数的实例。您必须传递Class&lt;T&gt;

更新:

查看@JDC 的回答。

【讨论】:

    【解决方案3】:

    在运行时这会返回一个 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;
        }
    }
    

    在我测试时效果很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2011-03-27
      • 1970-01-01
      相关资源
      最近更新 更多