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

Sne*_*kse 26 java compiler-construction generics 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 setObject(T object) {
        set(OBJECT, object);
    }
}
Run Code Online (Sandbox Code Playgroud)

和...

/** 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

编译时,我收到以下错误.

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中,据我所知,它使用与我的Ant构建相同的JDK.我已经看到了关于Sun编译器问题SO线程,但这似乎是针对动态声明类型的静态方法.

为什么我会收到此错误,更重要的是,我该如何解决这个错误?

到目前为止,我发现的唯一原因就是像我这样使用我的方法:

@SuppressWarnings({"unchecked"})
public T getObject() {
    return (T) get(OBJECT); //yuck
}
Run Code Online (Sandbox Code Playgroud)

告诉我我的裂缝,这是正确的方式是可以接受的.

Myk*_*ych 21

这是在Java SE 7中修复的虚拟错误.


Jér*_*nge 17

它不能编译,因为你的代码对泛型的期望过高 - >即<X> X部分:

public <X> X get(String property) { ... }
Run Code Online (Sandbox Code Playgroud)

在以下代码中:

public T getObject() {
  return get(OBJECT);
}
Run Code Online (Sandbox Code Playgroud)

你必须记住,在编译器实际开始编译Java代码之前,泛型总是"展开" .这是一个预处理步骤.

在你的情况下,编译器不知道用什么来取代X 在编译时.编译器需要确定X的类型,因为它需要针对T进行检查以验证代码.因此错误......

您的问题的解决方案是将<X> X替换为Object:

public Object get(String property) { ... }
Run Code Online (Sandbox Code Playgroud)

并添加一个演员:

public T getObject() {
  return (T) get(OBJECT);
}
Run Code Online (Sandbox Code Playgroud)

您将在编译时获得未经检查的转换警告,但您的代码将编译(所以是的,您的解决方法是有效的).

  • 但是为什么eclipse与这种代码一样好(并且也是intellij),用ant(和maven)完成的编译失败了? (4认同)
  • `public <X> X get(String property)`方法是我无法改变的第三方库的一部分. (2认同)
  • 好吧,我明白了(这个库真的不是很好写,哈哈).无论如何,正如你自己想象的那样,仅使用getObject()中的(T)转换也可以解决编译问题.遗憾的是 - 这里没有其他选择...... (2认同)