Java 为什么编译器声明不存在唯一的最大实例?

Java 为什么编译器声明不存在唯一的最大实例?,java,generics,compiler-construction,compiler-errors,javac,Java,Generics,Compiler Construction,Compiler Errors,Javac,我有以下课程: 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 setOb

我有以下课程:

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

告诉我“我快崩溃了”,这是可以接受的正确方式。

它无法编译,因为您的代码对泛型的期望太高->即,中的X部分:

public <X> X get(String property) { ... }
您必须记住,在编译器实际开始编译Java代码之前,泛型总是“展开的”。这是一个预处理步骤

在您的情况下,编译器不知道在编译时用什么替换X。编译器需要确定X的类型,因为它需要对照T检查它以验证代码。因此错误

您的问题的解决方案是用对象替换X:

public Object get(String property) { ... }
并添加一个演员阵容:

public T getObject() {
  return (T) get(OBJECT);
}

编译时,您将收到一个未经检查的强制转换警告,但您的代码将被编译(因此,是的,您的变通方法是有效的)。

方法类型参数通常是从该方法的参数隐式推断出来的。但是,请注意,
get
在参数和类型参数之间没有明确的关系:

public <X> X get(String property)
public X get(字符串属性)
类型推断是通常的路径,但是方法也可以用显式类型参数调用,就像类一样。格式大致遵循声明的格式,因此在Obj中可以

public T getObject() {
    return super.<T>get(OBJECT);
}
public T getObject(){
返回super.get(OBJECT);
}
您也可以直接使用
,但您仍然必须使用未选中的强制转换才能将其返回到
T
。注意显式参数需要一个限定符,通常是类的实例名。因为您的示例使用了超类的方法,所以它的引用通过
super
是隐式的

这并不能解决在非泛型类(
BaseModel
)中应用泛型方法(
xget
)的根本问题。请注意,库中的代码对类型参数进行强制类型转换。这种风格确实是将通用特性向后移植到非通用Java代码中的解决方案之一。看起来他们试图对库用户隐藏这一点,但由于他们没有泛化类,因此无法从实例推断类型(即,您确实希望有
Obj扩展BaseModel


[编辑:更正并解释了显式方法类型参数]

我刚刚在使用的项目中遇到了类似的问题。客户机代码充满了这样的行:

boolean foo = org.apache.pivot.json.JSON.get(item, "foo");
代码将在Eclipse中编译,但不使用命令行中的Maven或
javac
。看起来是的,但在更新到最新的JDK后我仍然可以看到它

由于
JSON
类是由Pivot提供的,因此我无法在自己的源代码树中修改它(在这个项目中,分叉库不是一个选项)

对我有效的解决方案来自bug报告中的第一个回复,将代码改为:

boolean foo = org.apache.pivot.json.JSON.<Boolean>get(item, "foo");
boolean foo=org.apache.pivot.json.json.get(项目“foo”);

这是在JavaSE7中修复的伪代码。

我现在无法用JDK7和一个较小的示例重现这一点。请注意,Eclipse使用自己的内部编译器进行编译@Paŭlo-这不能编译<代码>返回获取(对象)你是对的,正确的语法是“return-get(OBJECT);”。抱歉混合使用。
public X get(String属性)
方法是我无法更改的第三方库的一部分。好的,我明白了(这个库写得不是很好,哈哈)。无论如何,正如您自己所想,仅在getObject()中转换为(T)也可以解决编译问题。不幸的是,这里没有其他选择……事实上,这个库看起来像是实现异构容器的一次糟糕尝试……但是为什么eclipse可以(也可以是intellij)使用这种代码,而使用ant(以及maven)完成的编译失败了呢?这是一个解决方案,但不是最好的解决方案。代码很好。检查此链接问题可能是因为编译器太旧,或者。。。我不知道。代码
返回get(OBJECT)不编译。你是想选演员吗?哎呀,我忘了给你限定词了。我会解决的。不,强制转换和显式类型参数之间确实有区别。这里还有一些。如果您提前知道对象类型,这很有效,但是如果类型是在运行时作为类实例创建的一部分确定的(
newobj(new Foo())
),这将不起作用。感谢链接到缺陷!奇怪的是,我只是在Ubuntu上的OpenJDK 6上遇到了这种情况,而不是在Windows上的Java1.6。通过切换到OpenJDK 7,这个问题在我的Ubuntu机器上消失了。使用jdk 1.7编译代码,修复了这个问题
public T getObject() {
    return super.<T>get(OBJECT);
}
boolean foo = org.apache.pivot.json.JSON.get(item, "foo");
boolean foo = org.apache.pivot.json.JSON.<Boolean>get(item, "foo");