【问题标题】:Get generic class at compile time在编译时获取泛型类
【发布时间】:2013-08-20 09:39:32
【问题描述】:

虽然我知道由于类型擦除,您实际上无法在运行时获取泛型的类型,但我想知道是否可以在编译时获取它。

class ObjectHandle<T extends ObjType> {
    T obj;
    void setObj(T o) {
        obj = o;
    }
}

class ObjType {}
class SubObjType extends ObjType {}

...
ObjectHandle<SubObjType> handle = new ObjectHandle<SubObjType>();
...
ObjType obj = [method that returns an ObjType];
if(obj instanceof [handle's generic class, here SubObjType]) {
    handle.setObj(obj); // cast???
}

这里编译器知道handle 的泛型类型和我想要的东西,所以当我决定时我不必更改handleinstanceof 检查(和演员表)的类型更改类(在代码中,当然不是在运行时)。

【问题讨论】:

  • 但是编译器不知道obj的类型,所以无论如何你必须使用instanceof
  • 看起来你想要的只是你的 SubObjType 的简写,你可以在 C 中使用 typedef 来做这件事。 Java 没有。
  • 如果您不需要通用案例代码,并且您唯一担心的是代码中的实际类可能会发生变化,我只需将if 替换为assert handle instanceof SubObjType。或者您真的希望在代码中实际类型发生更改时跳过handle.setObj 调用?
  • @VGR:理想的做法是 ObjectHandle 中的一个方法,以确保 setObj() 获得正确的类,否则会抛出异常或其他东西。这只是该问题的解决方法。我有一个方法可以从文件中加载不同子类的对象并将它们作为超类(ObjType)返回。虽然 obj 应该是返回的 SubObjType,但除了在其上使用 instanceof 之外,没有其他方法可以判断。
  • @Alexei Kaigorodov:为什么编译器需要知道这一点? obj 是一个ObjType,所以检查它与ObjType 的子类对我来说似乎是有效的。编译器不应该删除instanceof,而是删除[handle's generic class, here SubObjType],并将其替换为[ObjectHandle&lt; __SubObjType__ &gt; handle] =&gt; SubObjType

标签: java generics compile-time


【解决方案1】:

由于泛型类型会被擦除,因此您需要在代码中的某处指定 java.lang.Class。一种方法是将其传递给泛型方法:

ObjType obj = /*...*/;
handleObj(obj, SubObjType.class);

// ...

private <T extends ObjType> void handleObj(ObjType obj,
                                           ObjectHandle<T> handle,
                                           Class<T> handleableObjClass) {
    if (handleableObjClass.isInstance(obj)) {
        handle.setObj(handleableObjClass.cast(obj));
    }
}

如果你不知道你在寻找什么 ObjType 的子类,你需要给 ObjectHandle 添加一个可具体化的 Class 属性,类似于 java.util.EnumSet 和 java.util.EnumMap 的做法:

class ObjectHandle<T extends ObjType> {

    T obj;

    private final Class<T> objectClass;

    ObjectHandle(Class<T> cls) {
        objectClass = Objects.requireNonNull(cls);
    }

    Class<T> getObjectClass() {
        return objectClass;
    }

    void setObj(T o) {
        obj = o;
    }
}

// ...
ObjectHandle<SubObjType> handle = new ObjectHandle<SubObjType>();
// ...

ObjectType obj = /*...*/;
if (handle.getObjectClass().isInstance(obj)) {
    handle.setObj(handle.getObjectClass().cast(obj));
}

【讨论】:

  • 嗯,我也会这样做。可悲的是,没有很酷的编译时方法。这并不能真正回答我正在寻找的东西,但那是因为似乎没有答案。无论如何,谢谢你清理这个。 :)
猜你喜欢
  • 2014-07-23
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 2015-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多