2017-05-24 329 views
3

为什么当我建立这个项目抛出一个错误(但不能同时运行单元测试)...不兼容的类型:推理变量E#1具有不兼容的上限枚举<E#2>

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:

显然,当我离开了 '扩展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时编译器不会抱怨原来的第一个例子?

回答

0

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

+0

听起来很合理,但我见过的例子之前我不需要传递类类型作为参数,只将泛型类型定义为返回类型,而且显然足够了。 ... 如果没有,那么GsonBuilder是如何知道的? fromJson方法与我的第一个示例非常相似。 ... 我想它是从Type参数中读取具体类型。那我该怎么做?尽管如此,这并不能解释为什么'fromJson'不需要类参数来提供必要的信息,就像您对我的示例所暗示的那样。 –

+0

研究类型推断。必须有一些事情可以告诉编译器推断什么。您没有向我们展示完整的示例,因此我们不知道该方法是如何使用的。也许有一个提供信息的分配上下文,但没有显示你为第一个例子做的事情。 –

+1

我编辑了我的问题两次,发现(部分)我正在寻找的答案。如果你能研究它并且再次回答(新)问题,我将不胜感激。 –