2

考虑以下函数:

public static <T> T doSomething(Document doc, String xpath, Class<T> returnType);

这个想法是处理 XML 文档,在指定的 xpath 检索对象,并返回指定类型的东西,足够简单。现在,假设我们想让它 if returnType.isEnum(),我们想把它当作我们想要检索 aString而不是 enum 类型,然后Enum.valueOf()在最后使用。

不幸的是,看起来

String returnedObj = String.class.cast(...); // Returned value from the actual XPath.evaluate() call
return Enum.valueOf(returnType, returnedObject);

不起作用,因为returnType不是Class<T extends Enum<T>>. 但是,您不能通过任何returnType一种方式真正塑造成那样Class.asSubclass()(至少没有不安全的铸造,我们试图避免这种情况)。

看起来你不能超载doSomething()来做一些特定于枚举的事情——即。

public static <T extends Enum<T>> T doSomething(Document doc, String xpath, Class<T> returnType);

因为这实际上是运行时的“相同签名”。

所以,问题是,有没有办法在一个方法中安全地完成所有这些,或者我需要一个单独的方法来专门处理枚举或诉诸不安全的演员表?

4

1 回答 1

1

我对这个问题有足够的兴趣尝试一下。我没有成功,但我认为值得在这里分享尝试,以便进一步讨论。

interface Evaluator {
  <T> T evaluate(String path, Class<? extends T> type);
}


final class Attempt implements Evaluator {
  @Override
  public <T> T evaluate(String path, Class<? extends T> type) {
    final Object result = evaluatePath(path, type);
    return type.cast(type.isEnum() ?
                     valueOf(type.asSubclass(Enum.class), (String)result) :
                     result);
  }


  private static Object evaluatePath(String path, Class<?> type) {
    /* This doesn't actually do anything meaningful, but that doesn't matter for now.
       Presumably it would make a call to something like XPath#evaluate().
     */
    return path;
  }


  private static <T extends Enum<T>> T valueOf(Class<T> type, String name) {
    return Enum.valueOf(type, name);
  }
}

此代码通过 IntelliJ IDEA 的 as-you-type 编译器,但在提交到真正的javac时失败:

[unchecked] unchecked method invocation:
  <T>valueOf(java.lang.Class<T>,java.lang.String) in Attempt is applied to
  (java.lang.Class<capture#474 of ? extends java.lang.Enum>,java.lang.String)

我发现错误消息令人费解,我认为这是将原始类型Enum(如Class<Enum>)传递给寻找参数化类型的方法的一个表达不佳的结果。

为了确认这里需要什么令人讨厌的转换,我鼓励其他人编辑(或复制和扩充)上面的代码以说明所需的更改。

于 2012-08-29T01:23:01.737 回答