从抽象类的子类调用Java方法

从抽象类的子类调用Java方法,java,abstract,unbounded-wildcard,Java,Abstract,Unbounded Wildcard,给定以下抽象类: public abstract class BaseVersionResponse<T extends BaseVO> { public abstract void populate(T versionVO); } 版本VOV1如下所示: public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) { BaseVersionR

给定以下抽象类:

public abstract class BaseVersionResponse<T extends BaseVO> {

    public abstract void populate(T versionVO);

}
版本VOV1如下所示:

public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version) {

    BaseVersionResponse<? extends BaseVO> specificVersionResponse = null;

    if (version.equalsIgnoreCase("V1")) {

        specificVersionResponse = new VersionResponseV1();

    } else if (version.equalsIgnoreCase("V2"))

        specificVersionResponse = new VersionResponseV2();

    return specificVersionResponse;
}

public BaseVO createVersionVO(String version) {

    BaseVO versionVO = null;

    if (version.equalsIgnoreCase("V1")) {

        versionVO = new VersionVOV1();

    } else if (version.equalsIgnoreCase("V2"))

        versionVO = new VersionVOV2();

    return versionVO;
}
public class VersionVOV1 extends BaseVO {

    private String fieldOne = null;
    private String fieldTwo = null;
    private String fieldThree = null;

    public String getFieldOne() {
        return fieldOne;
    }
    public void setFieldOne(String fieldOne) {
        this.fieldOne = fieldOne;
    }
    public String getFieldTwo() {
        return fieldTwo;
    }
    public void setFieldTwo(String fieldTwo) {
        this.fieldTwo = fieldTwo;
    }
    public String getFieldThree() {
        return fieldThree;
    }
    public void setFieldThree(String fieldThree) {
        this.fieldThree = fieldThree;
    }

}
当我试图编译这行代码时,我的问题出现了:

baseVersionResponse.populate(versionVO);
getVersionInfo(…)
中。我收到的信息如下:

BaseVersionResponse类型中的方法populate(capture#3-of?)不适用于参数(BaseVO)

在上面的
填充方法中

我的想法是(这显然是错误的),因为baseVersionResponse在代码中的这一点上实际上是一个特定的子实例,所以该类将确切地知道从该特定的子类调用哪个填充方法

我做错了什么?如果这不是正确的方法,有没有更好的方法


谢谢你抽出时间

如果您只是取出类型的捕获(即“”),并将其保留为未选中状态,那么它应该可以正常工作。即使使用类型对象也会编译

但是,根据您的具体示例,您可能需要的是以下方法:

public BaseVersionResponse<?> createVersionResponse(String version)
公共BaseVersionResponse createVersionResponse(字符串版本)
改为:

public BaseVersionResponse<? extends BaseVO> createVersionResponse(String version)
public-BaseVersionResponse
使用


BaseVersionResponse好的,我今天更仔细地看了一下。问题是,通配符虽然是正确的方式,但却阻止您执行以下操作:

BaseVO versionVO = createVersionVO(version);
因为
populate
调用需要BaseVO的扩展,而不是实际的BaseVO,这不符合条件。这意味着您不能直接传递versionVO变量

因此,为了保持类型检查,我认为这是很好的,因为您总是需要一个实现,将几乎所有内容都保留在上面,并将
BaseVersionResponse
类更改为类似以下内容:

public abstract class BaseVersionResponse<T extends BaseVO> {

    public T getVersion(BaseVO versionVO) {
        try {
            return (T) versionVO;
        } catch (ClassCastException e) {
            throw new IllegalArgumentException();
        }
    }

    public abstract void populate(BaseVO versionVO);

}
因此,我们将populate方法改为takebasevo,getVersion方法为我们进行转换。所有其他类型的检查仍然适用,我们可以开始了

强制转换使它感觉不那么干净,但是对于您正在使用的工厂方法来说,它确实是(我能想到的)保持类型声明和代码模式所做保证的唯一方法


希望有帮助

我认为应该在抽象类中更改方法参数。尝试更改populate(T versionVO)的参数类型;方法你能发布版本VOV1吗?@ElliotFrisch当然,我刚刚发布了版本VOV1@prudhvi我有点不确定你的意思。我应该将参数类型更改为什么?如果我将其更改为
,则在这一行上会出现编译错误:
baseVersionResponse=createVersionResponse(version)说明:类型不匹配:无法从BaseVersionResponse转换为BaseVersionResponse。这让我更仔细地研究了这个仍然有无限通配符的方法。如果我将这些更改为,那么当然我的工厂将不再工作,并且我得到以下错误类型不匹配:无法在此行上从VersionResponseV1转换为BaseVersionResponse:
…=新版本响应v1()。啊,错过了那个细节。我更新了我的答案。这将限制您显式地使用BaseVO的子类,这正是您在这个特定情况下想要的。你现在应该得到同样的结果。嗯,我仍然得到同样的编译错误。不过,我用你的建议更新了上面的原始代码,以便我们看到相同的东西。还有其他想法吗?我觉得我应该能够以某种方式工作……我会想出一个更好的答案。我认为这其中有一个根本性缺陷的症结;我现在真的有工作代码了!非常感谢。我确实觉得它不那么干净,因为它是显式铸造;我其实是想避免这种情况。也许有什么办法,我可以修改我对我的工厂所做的事情,以便它可以被清理?我必须调查一下。再次感谢…这确实解决了我发布的原始问题。很高兴能提供帮助。如果你真的遇到了另一个选择,我很想听听。但正如你所说,我认为你必须大幅修改你的方法,以获得“更干净”的结果。照目前的情况,主要的情况都得到了处理,边缘的情况也得到了适当的处理,代码也不会碍事,所以应该足够了。但这绝对是一个有趣的问题。
BaseVersionResponse<?>
BaseVersionResponse<? extends BaseVO>
BaseVO versionVO = createVersionVO(version);
public abstract class BaseVersionResponse<T extends BaseVO> {

    public T getVersion(BaseVO versionVO) {
        try {
            return (T) versionVO;
        } catch (ClassCastException e) {
            throw new IllegalArgumentException();
        }
    }

    public abstract void populate(BaseVO versionVO);

}
public void populate(BaseVO version) {
    VersionVOV1 versionVO = getVersion(version);
    this.setTestFieldOne(versionVO.getFieldOne());
    this.setTestFieldTwo(versionVO.getFieldTwo());
}