我有以下课程:
public class Obj<T> extends BaseModel {
public static final String OBJECT = "object";
public Obj(T object) {
setObject(object);
}
public T getObject() {
return get(OBJECT);
}
public void setObject(T object) {
set(OBJECT, object);
}
}
还有...
/** This is a 3rd party library class **/
public class BaseModel implements ModelData, Serializable {
//...members and stuff...
@SuppressWarnings({"unchecked", "rawtypes"})
public <X> X get(String property) {
X obj = null;
if (start > -1 && end > -1) {
Object o = map.get(property.substring(0, start));
String p = property.substring(start + 1, end);
if (o instanceof Object[]) {
obj = (X) ((Object[]) o)[Integer.valueOf(p)];
} else if (o instanceof List) {
obj = (X) ((List) o).get(Integer.valueOf(p));
} else if (o instanceof Map) {
obj = (X) ((Map) o).get(p);
}
} else {
obj = (X) map.get(property);
}
return obj;
}
}
编译时出现以下错误。
type parameters of <X>X cannot be determined; no unique maximal instance exists for type variable X with upper bounds T,java.lang.Object -> getObject()
在 Eclipse 中不会发生这种情况,据我所知,Eclipse 使用与我的 Ant 构建相同的 JDK。 我看过关于 Sun 编译器问题的 SO 线程,但这似乎是针对动态声明类型的静态方法。
为什么我会收到此错误,更重要的是,如何解决它?
到目前为止,我发现的唯一原因就是像这样输入我的方法:
@SuppressWarnings({"unchecked"})
public T getObject() {
return (T) get(OBJECT); //yuck
}
告诉我我已经崩溃了,这是正确的方法是可以接受的。
这是虚拟的 bug,已在 Java SE 7 中修复。
它无法编译,因为您的代码对泛型期望太多 -> 即:< X >中的
X 部分public <X> X get(String property) { ... }
在以下代码中:
public T getObject() {
return get(OBJECT);
}
你必须记住,泛型总是在编译器真正开始编译 Java 代码之前“展开”。这是一个预处理步骤。
在您的情况下,编译器不知道在编译时使用什么来替换 X。编译器需要确定 X 的类型,因为它需要对照 T 检查它以验证代码。因此出现错误... 解决您问题的方法是将
X 替换为对象:
< X >public Object get(String property) { ... }
并添加演员:
public T getObject() {
return (T) get(OBJECT);
}
您将在编译时收到未经检查的强制转换警告,但您的代码将编译(所以是的,您的解决方法是有效的)。
get
实参和类型形参之间没有明确的关系:
public <X> X get(String property)
类型推断是通常的路径,但也可以使用显式类型参数调用方法,就像类一样。格式大致遵循声明的格式,因此在 Obj 内部您可以有
public T getObject() {
return super.<T>get(OBJECT);
}
您也可以直接使用
<Object>
,但您仍然必须使用未经检查的强制转换将其恢复为
T
。请注意,显式参数需要限定符,通常是类的实例名称。由于您的示例使用了超类的方法,因此它的引用是通过 super
隐式进行的。这并不能解决在非泛型类 (
<X> X get
) 内部应用泛型方法 (
BaseModel
) 的根本问题。请注意,库中的代码对类型参数进行强制类型转换。这种风格确实是将通用功能反向移植到非通用 Java 代码中的解决方案之一。看起来他们试图向库用户隐藏这一点,但由于他们没有泛化该类,因此无法从实例推断出类型(即您确实想要拥有 Obj<T> extends BaseModel<T>
)。[编辑:更正并解释显式方法类型参数]
的项目中遇到了类似的问题。 客户端代码充满了这样的行:
boolean foo = org.apache.pivot.json.JSON.get(item, "foo");
代码可以在 Eclipse 中编译,但不能使用 Maven 或命令行中的
javac
。 它似乎是
Bug 6302954,但更新到最新的JDK后我仍然看到它。 由于
JSON
类是由 Pivot 提供的,所以我无法在自己的源代码树中修改它(在这个项目中不能选择分叉库)
对我有用的解决方案来自错误报告中的第一个回复,将代码更改为:boolean foo = org.apache.pivot.json.JSON.<Boolean>get(item, "foo");