![](/img/trans.png)
[英]How can I force Java to accept a conditional type for one of the parameters of a method call?
[英]How can I use inheritance for parameters type in a method call?
我正在為學校項目開發Java Web應用程序,並且我將盡可能地遵循MVC架構模式。 為此,我創建了一組JavaBean類,並使用Gson對這些實例的序列化和反序列化。 我遇到的問題表明,我還沒有完全理解Java中繼承和泛型的工作原理,因此我希望通過這個問題來闡明這些論點。
我有兩個抽象類Item
和ItemVariant
,它們分別由兩個bean類擴展,分別是CatalogItem
, ArchivedItem
和CatalogItemVariant
, ArchivedItemVariant
。 Item
一個ItemVariant
的集合,反之亦然, ItemVariant
一個ItemVariant
可以引用其父項目(我知道這會導致序列化過程中出現循環,但這不是我遇到的問題)。 所以,理想情況下,實例CatalogItem
應該總是指收集CatalogItemVariant
和實例CatalogItemVariant
應始終參考的一個CatalogItem
,同樣適用於ArchivedItem
和ArchivedItemVariant
。 但是,我對強迫這種關系不感興趣。 例如,允許讓CatalogItemVariant
的實例引用ArchivedItem
的實例。
當前,這兩個抽象類的代碼如下:
public abstract class Item implements Serializable {
...
protected Collection<ItemVariant> variants;
...
public <T extends ItemVariant> Collection<T> getVariants() {
return (Collection<T>) variants;
}
...
public <T extends ItemVariant> void setVariants(Collection<T> variants) {
this.variants = (Collection<ItemVariant>) variants;
}
}
public abstract class ItemVariant implements Serializable {
...
protected Item parentItem;
...
public <T extends Item> T getParentItem() {
return (T) parentItem;
}
...
public <T extends Item> void setParentItem(T parentItem) {
this.parentItem = parentItem;
}
...
}
這會產生未經檢查的強制警告,我知道這可能不是最優雅的解決方案。 但是,這不是我遇到的主要問題。
擴展這兩個類的Bean類只是簡單地添加了幾個屬性,以及它們的getter和setter,這些具體類的實例是整個應用程序中實際使用的實例。 現在是真正的問題:例如,考慮以下必須反序列化為CatalogItemVariant
實例的JSON字符串。
{"parentItem":{"name":"Sample name","category":"Sample category","color":"Sample color"},"size":"Sample size"}
理想情況下,應該將parentItem
反序列化為CatalogItem
parentItem
形式,但是鑒於這些類當前的設計方式,Gson嘗試創建Item
的實例,該實例是抽象的,因此導致以下異常:
java.lang.RuntimeException: Failed to invoke public model.transfer.catalog.Item() with no args
要解決此問題,我想到了使Item
中的ItemVariant
和setVariants
中的setParentItem
這兩個方法ItemVariant
抽象,從而迫使它們的子類兩個重寫它們。 像這樣:
public abstract class ItemVariant implements Serializable {
...
protected Item parentItem;
...
public abstract <T extends Item> void setParentItem(T parentItem);
...
}
public class CatalogItemVariant extends ItemVariant {
...
@Override
public void setParentItem(CatalogItem parentItem) {
this.parentItem = parentItem;
}
...
}
但這是行不通的,因為CatalogItem
類型與T
不匹配,從而使@Override
注釋無效。
一種解決方法是向Servlet發送反序列化對象的兩個單獨的JSON字符串,一個用於item變量,一個用於其父項,然后使用正確的類將它們都反序列化為兩個不同的對象(第一個的CatalogItem
和第二個,使用CatalogItemVariant
),然后使用setParentItem()
手動設置新CatalogItemVariant
實例的屬性parentItem
。 當然,在應用此解決方案時,item變體的JSON字符串必須缺少其parentItem
字段。 有更好的解決方案嗎? 如果是這樣,我應該如何重新設計受此問題影響的類和方法?
編輯 :由於已經要求我提供實際的代碼,所以這是我使用的類的簡化版本:
public abstract class Item implements Serializable {
private static final long serialVersionUID = -6170402744115745097L;
protected String name;
protected String category;
protected String color;
protected Collection<ItemVariant> variants;
public String getName() {
return this.name;
}
public String getCategory() {
return this.category;
}
public String getColor() {
return this.color;
}
public <T extends ItemVariant> Collection<T> getVariants() {
return (Collection<T>) variants;
}
public void setName(String name) {
this.name = name;
}
public void setCategory(String category) {
this.category = category;
}
public void setColor(String color) {
this.color = color;
}
public <T extends ItemVariant> void setVariants(Collection<T> variants) {
this.variants = (Collection<ItemVariant>) variants;
}
}
public abstract class ItemVariant implements Serializable {
private static final long serialVersionUID = 4245549003952140725L;
protected Item parentItem;
protected String size;
public <T extends Item> T getParentItem() {
return (T) parentItem;
}
public String getSize() {
return size;
}
public <T extends Item> void setParentItem(T parentItem) {
this.parentItem = parentItem;
}
public void setSize(String size) {
this.size = size;
}
}
public class CatalogItem extends Item implements Serializable {
private static final long serialVersionUID = 993286101083002293L;
protected String description;
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
public class CatalogItemVariant extends ItemVariant implements Serializable {
private static final long serialVersionUID = -2266390484210707778L;
protected Integer availability;
public Integer getAvailability() {
return availability;
}
public void setAvailability(Integer availability) {
this.availability = availability;
}
}
我遇到的錯誤可以通過運行以下代碼片段進行模擬,並在最后一行中拋出:
Gson gson = new GsonBuilder().create();
CatalogItem catalogItem;
CatalogItemVariant catalogItemVariant;
CatalogItemVariant deserializedCatalogItemVariant;
catalogItem = new CatalogItem();
catalogItem.setName("Sample name");
catalogItem.setCategory("Sample category");
catalogItem.setColor("Sample color");
catalogItemVariant = new CatalogItemVariant();
catalogItemVariant.setSize("Sample size");
catalogItemVariant.setParentItem(catalogItem);
String serializedCatalogItemVariant = gson.toJson(catalogItemVariant); // Builds a JSON string of the object to serialize
System.out.println(serializedCatalogItemVariant); // Prints the JSON string of the serialized object which is fed for deserialization in the next instruction
deserializedCatalogItemVariant = gson.fromJson(serializedCatalogItemVariant, CatalogItemVariant.class);
為了澄清起見,我完全理解該錯誤是由於這些類的設計方式引起的,並且我不希望程序的行為有所不同。 我只想了解是否有一種方法可以使用泛型和繼承來重新設計這些類,如果可以,那是什么方法。
對於遇到此問題的任何人,請看一下這個非常簡單的解決方案!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.