简体   繁体   English

Java-从抽象类的子级中调用方法

[英]Java - Calling method from child of abstract class

Given the following abstract class: 给定以下抽象类:

public abstract class BaseVersionResponse<T extends BaseVO> {

    public abstract void populate(T versionVO);

}

and the following 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());
}

I desire to do something like this from a calling method: 我希望通过调用方法执行以下操作:

public void getVersionInfo(String version) {

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

    baseVersionResponse = createVersionResponse(version);

    versionVO = createVersionVO(version);

    baseVersionResponse.populate(versionVO);

}

where createVersionResponse(...) and createVersionVO(...) look like this: 其中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;
}

and VersionVOV1 looks like this: 和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;
    }

}

My problem arises when I try to compile this line of code: 当我尝试编译以下代码行时,就会出现我的问题:

baseVersionResponse.populate(versionVO);

in getVersionInfo(...) . getVersionInfo(...) I'm getting a message that looks like this: 我收到一条看起来像这样的消息:

The method populate(capture#3-of ?) in the type BaseVersionResponse is not applicable for the arguments (BaseVO) 类型BaseVersionResponse的方法populate(capture#3-of?)不适用于参数(BaseVO)

on the populate method above. 在上面的populate方法上。

My thought was (which is apparently incorrect) that since the baseVersionResponse is, at this point in the code, actually a specific child instance, that the class would know exactly which populate method to call from that specific child class. 我的想法是(显然是不正确的),因为在代码的这一点上,baseVersionResponse实际上是一个特定的子实例,该类将确切知道要从该特定子类中调用哪个填充方法。

What am I doing wrong here? 我在这里做错了什么? Is there a better way to do this if this isn't the correct approach? 如果这不是正确的方法,还有更好的方法吗?

Thank you for your time! 感谢您的时间!

If you just take out the capture of type (the "<?>"), and leave it unchecked, it should work just fine. 如果您只捕获类型(“ <?>”)的捕获,并且不选中它,它应该可以正常工作。 Even using type Object would have compiled. 即使使用Object类型也可以进行编译。

But, given your specific example, what you probably want is the method: 但是,给定您的特定示例,您可能想要的是方法:

public BaseVersionResponse<?> createVersionResponse(String version)

Changed to: 变成:

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

Then, instead of using 然后,而不是使用

BaseVersionResponse<?>

use 采用

BaseVersionResponse<? extends BaseVO>

Since you know that the return type will be one of those things that implements the interface/class. 既然您知道返回类型将是实现接口/类的那些事情之一。

Ok, I took a better look at this today. 好的,我今天对此做了更好的了解。 The problem is that the wildcard, while the right way to go, precludes you from doing: 问题在于,通配符虽然是正确的方法,但却使您无法执行以下操作:

BaseVO versionVO = createVersionVO(version);

Because the populate call wants an extension of BaseVO, not an actual BaseVO, which doesn't qualify. 因为populate呼叫需要扩展 BaseVO,而不是不符合条件的实际BaseVO。 That means you can't pass that versionVO variable directly. 这意味着您不能直接传递那个versionVO变量。

So, to keep the type checking in place, which I think is good because you'll always want an implementation, leave pretty much everything as-is above, and change your BaseVersionResponse class to something like: 因此,将类型检查保持在适当的位置,我认为这很好,因为您将始终需要实现,将上面的所有内容保持不变,然后将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);

}

So, populate method now takes a BaseVO, and there's a new getVersion method to do some explicit casting for us. 因此,填充方法现在需要一个BaseVO,并且有一个新的getVersion方法可以为我们做一些明确的转换。 This should be ok since we know that the factory will always supply the right thing, but if another caller doesn't, an IllegalArgumentException is thrown. 这应该没问题,因为我们知道工厂将始终提供正确的东西,但是如果另一个调用者不提供,则抛出IllegalArgumentException

Now, in your response class implementation, change the populate method accordingly: 现在,在您的响应类实现中,相应地更改populate方法:

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

So, we've changed the populate method to take BaseVO, and the getVersion method does the casting for us. 因此,我们将populate方法更改为采用BaseVO,而getVersion方法为我们进行了强制转换。 All the other type checks still apply, and we're good to go. 所有其他类型检查仍然适用,我们很好。

The casting makes it feel not as clean, but for the factory approach you're using, it's really the only way (I can think of) to keep the guarantees made by the type declarations and the code pattern in tact. 强制转换使它感觉不那么干净,但是对于您正在使用的工厂方法而言,它实际上是使类型声明和代码模式保持不变的唯一方法(我能想到)。

Hope that helps! 希望有帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM