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

亚历克斯·马萨(Alex Massa)

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

我有两个抽象类ItemItemVariant,它们通过各自两个分别bean类,扩展CatalogItemArchivedItemCatalogItemVariantArchivedItemVariant的等式Item可以引用的集合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

为了解决这个问题,我想使这两种方法setVariantsItemsetParentItemItemVariant抽象的,从而迫使其子类2个覆盖它们。像这样:

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注释无效。

一种解决方法,以这将被发送到该反序列化对象两个单独的JSON字符串,一个用于项变体,一个用于它的父项的服务程序,使用正确的类(反序列化两者成两个不同的对象CatalogItem的第一个和CatalogItemVariant用于第二个),然后使用手动设置parentItemCatalogItemVariant实例的属性setParentItem()当然,在应用此解决方案时,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);

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

亚历克斯·马萨(Alex Massa)

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

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在TypeScript中调用类型参数的静态方法

如何在方法调用时找到方法参数的类型?

Perl:如何在多重继承中调用特定方法?

如何在多级继承中调用父级方法

如何在F#中调用因参数类型重载的方法?

如何在不指定类的情况下使用显式类型参数调用Java方法?

如何在Julia中以更复杂的类型使用继承

如何在Swift 3中使用关联类型的参数调用泛型函数

如何使用Func类型的Expression作为参数调用方法

如何在JPA中混合继承类型

为什么在继承中调用固定数据类型参数的对象类参数方法亚麻子

如何在“真实”方法中调用模拟方法时使用参数?

如何在继承层次结构中调用具有默认参数的构造函数?

如何在Scala中参数化具有继承类型的函数

如何在实例方法中调用类型方法

使用继承方法后,如何在使用继承方法的类中重置或替换函数?

如何在 VUE.js 方法中使用函数中的参数调用函数?

如何在单个约束中同时使用方法和类类型参数?

Python-Tkinter-如何在命令参数中调用方法

如何在 Angular 的 ngOnInit 中调用参数化方法?

如何在Java中调用参数化方法?

如何在JavaScript事件中通过参数调用页面方法?

如何在 salesforce apex 类中调用参数化方法

您如何在Java中调用泛型类型的方法?

如何在泛型方法中引用类型参数的值

如何在Android Studio上使用View参数调用方法

如何在Swift中使用CVaListPointer参数调用方法

如何在Android Studio中使用View参数调用方法

如何在方法声明而不是类中使用类型参数