不兼容的类型:推理变量E#1具有不兼容的上限Enum <e#2>

时间:2017-05-24 18:55:08

标签: java generics enums

为什么在构建项目时会抛出错误(但在运行unittests时却没有...)

protected <E extends Enum<E>> E getEnum(JSONObject jsonObject, String propertyName, Type type)
{
    String jsonString = jsonObject.optString(propertyName, null);
    return new GsonBuilder().create().fromJson(jsonString, type);
}

...虽然这完美有效(注意区别 - 最后一个参数 - 未使用!):

protected <E extends Enum<E>> E getEnum(JSONObject jsonObject, String propertyName, Type type, Class<E> clazz)
{
    String jsonString = jsonObject.optString(propertyName, null);
    return new GsonBuilder().create().fromJson(jsonString, type);
}

错误:

   warning: [options] bootstrap class path not set in conjunction with -source 1.7 C:\Projects\bla\bla\bla.java:32: error: incompatible types: inference variable E#1 has incompatible upper bounds Enum<E#2>,Termination
    Termination termination = getEnum(jsonObject, "termination", Termination.TYPE);                                                         
    where E#1,E#2 are type-variables:
      E#1 extends Enum<E#1> declared in method <E#1>getEnum(JSONObject,String,Type)
      E#2 extends Termination

我该怎么做才能改善这个?

修改

作为附加信息:这就是我调用方法的方法(使用第二个例子,第一个例子已经显示在错误信息中):

Termination termination = getEnum(jsonObject, "termination", Termination.TYPE, Termination.class).

这是该枚举的简化版本:

public enum Termination
{
    @SerializedName("endDate")END_DATE, 
    @SerializedName("recurrenceCount")COUNT,
    @SerializedName("forever")FOREVER;

    public static final java.lang.reflect.Type TYPE = new TypeToken<Termination>(){}.getType();
}

现在我明白了 - 由于类型推断 - 我显然需要定义类类型,如第二个例子所示。但是,这不是我的问题。我想知道1:为什么Gson库能够像我一样完成相同的操作(据我在下面的代码示例中看到),以及2:为什么在大多数情况下这不会编译,同时运行unittests没问题。

Gson示例代码(两个示例中调用的方法):

@SuppressWarnings("unchecked")
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
  if (json == null) {
    return null;
  }
  StringReader reader = new StringReader(json);
  T target = (T) fromJson(reader, typeOfT);
  return target;
}

编辑2:

显然当我省略'extends Enum'部分时,编译器不再抱怨,所以我不需要将类型作为参数传递。 (这看起来更像是Gson示例,这就是为什么它为该代码编译但在第一个示例中没有为我编译的原因)。所以我的第一个例子现在变成了:

protected <E> E getEnum(JSONObject jsonObject, String propertyName, Type type)
{
    String jsonString = jsonObject.optString(propertyName, null);
    return new GsonBuilder().create().fromJson(jsonString, type);
}

当然我还是要扩展E以确保该方法只能用于返回枚举。

剩下的问题:

  1. 如何改进代码来解决这个问题?
  2. 为什么不将具体类型作为参数传递,以及为什么在扩展Enum时它不起作用?
  3. 为什么编译器在运行unittests时没有抱怨原来的第一个例子?

1 个答案:

答案 0 :(得分:0)

第一个示例中的type参数无法知道要替换的具体类型。参数列表中必须有信息才能解决此问题。在第二个示例中,Class<E>参数提供了必要的信息。