Java - 从摘要 class 的 child 调用方法

Java - Calling method from child of abstract class

给定以下摘要class:

public abstract class BaseVersionResponse<T extends BaseVO> {

    public abstract void populate(T versionVO);

}

和以下 child class:

public class VersionResponseV1 extends BaseVersionResponse<VersionVOV1>
{
    protected String testFieldOne;
    protected String testFieldTwo;

    public String getTestFieldOne() {
        return testFieldOne;
    }  
    public void setTestFieldOne(String value) {
        this.testFieldOne = value;
    }
    public String getTestFieldTwo() {
        return testFieldTwo;
    }  
    public void setTestFieldTwo(String value) {
        this.testFieldTwo = value;
    }

    @Override
    public void populate(VersionVOV1 versionVO) {

        this.setTestFieldOne(versionVO.getFieldOne());
        this.setTestFieldTwo(versionVO.getFieldTwo());
}

我想通过调用方法做这样的事情:

public void getVersionInfo(String version) {

    BaseVO versionVO = null;
    BaseVersionResponse<? extends BaseVO> baseVersionResponse = null;

    baseVersionResponse = createVersionResponse(version);

    versionVO = createVersionVO(version);

    baseVersionResponse.populate(versionVO);

}

其中 createVersionResponse(...)createVersionVO(...) 看起来像这样:

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

VersionVOV1 看起来像这样:

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(...) 中。我收到一条看起来像这样的消息:

The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO)

关于上面的 populate 方法。

我的想法是(这显然是不正确的)因为 baseVersionResponse 在代码的这一点上实际上是一个特定的 child 实例,所以 class 会确切知道哪个填充方法从特定的 child class.

调用

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

感谢您的宝贵时间!

如果您只是取出类型捕获(“”),并且不选中它,它应该可以正常工作。即使使用类型 Object 也会编译。

但是,鉴于您的具体示例,您可能想要的是方法:

public BaseVersionResponse<?> createVersionResponse(String version)

更改为:

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

然后,而不是使用

BaseVersionResponse<?>

使用

BaseVersionResponse<? extends BaseVO>

因为您知道 return 类型将是实现 interface/class 的那些东西之一。

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

BaseVO versionVO = createVersionVO(version);

因为 populate 调用需要 BaseVO 的 扩展 ,而不是不符合条件的实际 BaseVO。这意味着你不能直接传递那个 versionVO 变量。

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

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 方法现在采用 BaseVO,并且有一个新的 getVersion 方法可以为我们进行一些显式转换。这应该没问题,因为我们知道工厂将始终提供正确的东西,但如果另一个调用者不提供,则会抛出 IllegalArgumentException

现在,在您的响应 class 实施中,相应地更改填充方法:

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

因此,我们更改了填充方法以采用 BaseVO,getVersion 方法为我们进行转换。所有其他类型检查仍然适用,我们可以开始了。

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

希望对您有所帮助!