1

考虑下面的例子。

为什么不允许我使用BImpl作为方法doSomething3的参数类型?当我说“不允许”时,我的意思是 Eclipse 抱怨接口AInf中的 doSomething3 方法没有实现。

interface AInf
{
    AInf doSomething();
    BInf doSomething2();
    void doSomething3(BInf param);
}


interface BInf
{

}

class AImpl implements AInf
{

    @Override
    public AImpl doSomething() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public BImpl doSomething2() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void doSomething3(BImpl param) // This method is not overriding the doSomething3(BInf param) from the AInf
    {
        // TODO Auto-generated method stub
    }
}

class BImpl implements BInf
{

}
4

5 回答 5

3

因为doSomething3(BImpl param)没有实现doSomething3(BInf param)

BInf可以有许多实现,并且该方法应该适用于所有实现,而不仅仅是一个。

始终牢记扩展类或实现接口定义了is a关系。所有扩大/缩小的规则都是由此产生的逻辑结果。

如果你用一个具体的例子来想象它会更容易:金钱。硬币就是钱,纸币也是钱。

如果您去一家决定将您购买的零钱限制为硬币的商店,这可能会很烦人,但这是合法的。没关系,因为它不会违反合同,他们总是在退钱。

但是当你在一家他们应该接受钱而他们不会接受你的硬币的商店里,那就不行了。

于 2012-08-08T11:54:18.230 回答
3

您必须具有与接口相同的类型。

界面说它会接受

void doSomething3(BInf param);

这意味着它将接受BInf任何子类型(因为可以预期它们的行为相同 - 请参阅Liskov Substitution Princple

您的实施不遵守本合同

public void doSomething3(BImpl param)

这个实现说我只会为 工作BImpl,但什么也没说BInf

(针对@IsmerSlomic 的问题进行编辑)

对于返回类型,Java 允许协变返回类型。这不会破坏 LSP,因为它返回的东西至少保证是接口中的返回类型。如果返回类型更特殊,那么通过 LSP,它仍然会做与返回原始接口相同的事情。

于 2012-08-08T11:55:25.940 回答
0

其声明为:

void doSomething3(BInf param);

但是您尝试使用不同的类型实现:

public void doSomething3(BImpl param)

Binf 和 BImpl

于 2012-08-08T11:53:32.717 回答
0

问题是 doSomething3 将 Bimpl 作为参数,但界面显示参数是 BInf(BImpl 不是 BInf)。并且由于有一个 @Override 注释,您告诉编译器您正在覆盖接口中的方法,您显然不是,因此是错误。

于 2012-08-08T11:54:58.893 回答
0

您可以返回 AImpl 和 BImpl 因为它们是协变返回类型(或者简单地说,所有 AImpl 对象都是 AInf 对象,并且所有 BImpl 对象都是 BInf 对象,因此调用者知道它正在返回接口中声明的 AInf 或 BInf 对象)。

这不适用于方法参数,因为您无法控制传递给 doSomething3() 方法的内容,因此无法保证 BInf 参数实际上是 BImpl。

于 2012-08-08T11:59:23.553 回答