2017-05-24 32 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

我編輯了我的問題兩次,發現(部分)我正在尋找的答案。如果你能研究它並且再次回答(新)問題,我將不勝感激。 –