如何在方法调用中对参数类型使用继承?

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

我正在为一个学校项目开发一个 Java 网络应用程序,我尽可能地遵循 MVC 架构模式;为此,我创建了一组 JavaBean 类,并使用 Gson 对这些实例进行序列化和反序列化。我遇到的问题表明我还没有完全理解继承和泛型在 Java 中是如何工作的,所以我希望通过这个问题阐明这些论点。

我有两个abstract 类 ItemItemVariant,分别扩展了两个bean 类,分别是CatalogItemArchivedItemCatalogItemVariantArchivedItemVariantItem 的实例可以引用 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,这些具体实例 类 是整个应用程序实际使用的实例。现在真正的问题来了:举个例子,考虑下面的 JSON 字符串,它必须被反序列化为 CatalogItemVariant.

的实例
{"parentItem":{"name":"Sample name","category":"Sample category","color":"Sample color"},"size":"Sample size"}

理想情况下,parentItem 应该被反序列化为 CatalogItem 的一个实例,但是考虑到那些 类 当前设计的方式,Gson 试图创建一个 Item 的实例],这是抽象的,因此会导致以下异常:

java.lang.RuntimeException: Failed to invoke public model.transfer.catalog.Item() with no args

为了解决这个问题,我想到了将 Item 中的 setVariantsItemVariant 中的 setParentItem 这两个方法抽象化,从而强制它们的子 类 两个覆盖它们。像这样:

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;
    }
    ...
}

但这不起作用,因为类型 CatalogItemT 不匹配,使得 @Override 注释无效。

解决此问题的方法是向反序列化对象的 servlet 发送两个单独的 JSON 字符串,一个用于项目变体,一个用于其父项目,使用更正 类(第一个为 CatalogItem,第二个为 CatalogItemVariant),然后使用 [=] 手动设置新 CatalogItemVariant 实例的属性 parentItem 48=]。当然,在应用此解决方案时,项目变体的 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);

澄清一下,我完全理解错误是由这些 类 的设计方式引起的,我不希望程序的行为有所不同;我只是想了解是否有一种方法可以使用泛型和继承来重新设计那些 类,如果可以,那是什么方法。

对于遇到这个问题的任何人,请查看非常简单的解决方案!