循环中的泛型,试图避免演员

时间:2017-05-18 04:13:48

标签: java generics

我在循环中有一个方法调用,目前无法编译:

for (Example example : Util.getExample(List.class)) {
    // Do something with example
}

的Util:

public class Util {
    public <T> T getExample(Class<T> clazz) {
        //...
    }
}

明显的解决方法是将回复从getExample强制转换为List<Example>。我想知道:是否有另一种方法可以避免演员表?

更多信息:

海报要求提供更多信息,所以这里......

我已经构建了一个围绕注释处理的框架,该框架编写代码来访问和改变类成员(构造函数,字段和方法)。该框架支持ParcelerTransfuse,并允许我在编译期间识别属性并生成访问或修改所述属性的代码。对于私有属性(私有构造函数,私有字段,私有方法),我使用实用程序来执行这些操作(Parceler'sTransfuse's)以通过反射来破坏封装。

Parceler具有在序列化期间展开集合的功能,以便序列化给定集合的成员。对于私有集合,InjectionUtil用于在循环中访问这些属性:

for (Example example : InjectionUtil.getField(List.class, Container.class, container, "exampleField")) {
    // ...
}

这是我目前面临的bug,因此,为什么我要求避免演员。我宁愿不投,因为我想在一般情况下生成一些代码来访问类型并尊重Java泛型。

3 个答案:

答案 0 :(得分:4)

如果您的getExample方法应该始终返回列表,那么是,将其返回类型更改为List<T>。但是,由于您将List.class作为参数传递,看起来您希望有一个方法可以返回列表和非列表,具体取决于您传递的类对象。

如果是这样,那就不会像你希望的那样工作。在这种情况下,您的方法仅返回原始类型List。要让它返回List<Example>,您必须将其传递给假设的List<Example>.class,但是没有这样的事情。通用类型参数在编译时被擦除,因此List<Example>List<String>实际上都是同一个类;它们没有单独的类对象,因此类对象参数不能告诉您的方法它应该返回什么类型的列表。

您可能需要尝试不同的设计方法。由于这显然是一个简化的示例,如果您发布有关您实际尝试完成的更多详细信息,您可能会获得更多帮助。

答案 1 :(得分:2)

在这种情况下可以使用Guava的TypeToken,因为List<Foo>.class无效。通过创建匿名类来使用TypeToken。因为匿名类保留了它们的通用签名,所以这有效。

for (Example foo : Util.getExample(new TypeToken<List<Example>>() {}) {
    // do stuff
} 

// utils
public <T> T getExample(TypeToken<T> typeToken) {
    Type type = typeToken.getType();
    // get example
}

TypeToken比仅使用Class更具体。您也可以使用普通Type作为参数,这样您仍然可以为它提供一个类。这就是Gson的做法。

答案 2 :(得分:0)

我认为这是一个设计问题......

由于您调用的Util中的方法被称为getExamples,因此修复它可能也是合理的,以返回一些集合,其中元素是Example类的实例。

getExamples更改为类似的内容是合理的吗?:

class Util {

  public static <C extends Collection<? supper Example>> getExamples(final Supplier<C> factory) {
       final C result = factory.get();
       // here goes the code that adds the examples to the result collection
       // using add or addAll.
       return result;
  } 

}

例如,如果你想使用List<Example>来实现ArrayList<E>,那么你会这样做:

List<Example> examples = Util.getExamples(ArrayList<Example>::new);

尝试传递返回的集合类对象引用(例如,List.class,ArrayList.class)不会起作用,因为getExamples中的代码将很难(a)弄清楚如何调用适当的构造函数使用反射来实例化结果(如果只传递一个接口类对象,如List.class,则有些不可能)和(b)将原始类型的返回转换为使用Example作为元素类型的泛型类型。后者是微不足道的,但它不尽可能整洁,因为它会产生警告。

在使用代码中委托明确指示如何实例化结果集合更为直接。

如果你没有返回Collection并在getExamples中使用add和addAll等方法,那么也许你应该从java流API中借用Collectors框架。