簡體   English   中英

如何在方法調用中對參數類型使用繼承?

[英]How can I use inheritance for parameters type in a method call?

我正在為學校項目開發Java Web應用程序,並且我將盡可能地遵循MVC架構模式。 為此,我創建了一組JavaBean類,並使用Gson對這些實例的序列化和反序列化。 我遇到的問題表明,我還沒有完全理解Java中繼承和泛型的工作原理,因此我希望通過這個問題來闡明這些論點。

我有兩個抽象類ItemItemVariant ,它們分別由兩個bean類擴展,分別是CatalogItemArchivedItemCatalogItemVariantArchivedItemVariant Item一個ItemVariant的集合,反之亦然, ItemVariant一個ItemVariant可以引用其父項目(我知道這會導致序列化過程中出現循環,但這不是我遇到的問題)。 所以,理想情況下,實例CatalogItem應該總是指收集CatalogItemVariant和實例CatalogItemVariant應始終參考的一個CatalogItem ,同樣適用於ArchivedItemArchivedItemVariant 但是,我對強迫這種關系不感興趣。 例如,允許讓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中的ItemVariantsetVariants中的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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM