4

考虑一下我在 Java 中有一个抽象类的情况;

public abstract class Foo
{
    public abstract int myOperation();
}

现在,它的一些子类可能会像这样覆盖 myOperation;

class A extends Foo
{
    public int myOperation()
    {
            // Do stuff
    }
}

但是,如果一个子类想要返回一些其他数据类型,例如;

class A extends Foo
{
    public Object myOperation()
    {
        // Do stuff
    }
}

我希望方法名称相同,以保持设计完整,以便客户端不必选择调用哪个方法。除了具有单独的方法(其中一个是空实现或使用 Object 作为返回类型)之外,是否有解决方法?或者这是一个非常糟糕的面向对象设计的例子?

我听说过 C++ 中的协变返回类型,并想知道 Java 是否有其他机制。

我也可以在这里自由使用界面。

4

6 回答 6

8

你不能。既不使用继承,也不使用接口。这将是一个编译器错误,因此您根本无法运行您的程序。

您可以返回java.lang.Object并返回您想要的任何对象。如果您需要返回一个原语,您可以返回它的对象包装器。

于 2012-07-14T16:22:10.760 回答
7

“这是面向对象设计的一个非常糟糕的例子吗?”是的。你不能这样做。

于 2012-07-14T16:23:25.207 回答
5

Java 具有协变返回类型,但返回类型必须更具体,而不是更具体。如果父类中的一个方法返回int,那么它的所有子类型也必须这样做,否则这种方法的调用者并不真正知道它得到的是什么类型。

Foo foo = new A()
int i = foo.method();

如果 method() 返回任何内容,但int此语句不再有意义。

当你可以做的是,如果超类中的方法返回Object并且一个服务类返回,Number那么两者的子类都可以返回Integer

于 2012-07-14T16:24:04.503 回答
3

当您使用返回类型作为派生即协变量时,您可以有不同的数据类型。当您使用原始数据类型时,您无法更改它。

如果超类方法是任何派生数据类型,而在子类中覆盖返回类型可以是相同的派生数据类型或子类派生数据类型。

于 2012-07-14T16:32:14.167 回答
2

这是不可能的,因为在抽象类中声明的方法定义了一个协定:它返回一个 int。所有实现都必须遵守该契约。如果你这样做会发生什么:

Foo foo = new A();
int i = foo.myOperation();

它会中断,因为 myOperation 不会返回int. 这就是为什么它是不允许的。

但是,允许的是以下内容:

public abstract class Foo {
    public abstract Object myOperation();
}

public class A extends Foo {
    @Override
    public String myOperation() {
        return "some string";
    }
}

在这种情况下,合同得到尊重。该方法必须返回一个Object,它返回一个String,而String就是一个Object。

于 2012-07-14T16:26:17.430 回答
2

你不能这样做,因为它会破坏Foo.

A a = new A();
someUtilityMethod(a);

...

void someUtilityMethod(Foo foo){
   int i = foo.myOperation();    // This would break
}

这个原则被称为Liskov 替换原则,它是构建 OO基础。

于 2012-07-14T16:29:31.127 回答