3

只是在玩界面,我有一个我无法真正理解的问题。

以下代码不运行,这是我期望的行为,因为接口方法要求该方法适用于任何对象,并且实现的方法已将签名更改为仅允许字符串对象。

interface I {
    public void doSomething(Object x);
}

class MyType implements I {
    public void doSomething(String x) {
        System.out.println(x);
    }
}

然而,使用下面的代码块,我很震惊地看到它确实有效。我认为它不起作用,因为我们期望返回一个对象,而实现的方法只会返回一个字符串对象。为什么会这样?这里传递参数和返回类型这两个原则有什么区别?

interface I {
    public Object doSomething(String x);
}

class MyType implements I {
    public String doSomething(String x) {
        System.out.println(x);
        return(x); 
    }
}
4

8 回答 8

3
public Object doSomething(String x);

必须返回一些东西。事实上,任何东西,只要它是某种类型的对象。所以如果你实现

public String doSomething(String x) {stuff}

这很好,因为它确实返回了一个对象。它将返回的对象始终是 String 的事实没什么大不了的。

第一个示例不起作用的原因是,仅接受字符串比接受任何对象更具限制性。但是只返回字符串就可以了。

打个比方,假设你有一份粉刷建筑物的合同,你将雇佣一些员工来帮助你。合同要求您雇用任何适用的油漆工,无论他们有多高,但没有指定使用什么颜色的油漆。如果您只雇用超过 6 英尺高的画家(这是输入,只接受 String 而不是所有 Object),您将违反合同。但是选择只用蓝色油漆(只返回字符串)就可以了,因为合同没有指定颜色,只是你必须给建筑物涂漆。

于 2012-05-14T15:57:09.847 回答
2

这与 Java SE 5.0 中引入的协变返回类型有关。您可以在http://docs.oracle.com/javase/tutorial/java/javaOO/returnvalue.html
中查看更多详细信息

于 2012-05-14T16:07:09.397 回答
2

它之所以有效,是因为 aString是一个Object.

于 2012-05-14T15:53:04.827 回答
2

From the java language specification:

Return types may vary among methods that override each other if the return types are reference types. The notion of return-type-substitutability supports covariant returns, that is, the specialization of the return type to a subtype.

So in other words, it works as you did it, but it would not work if the return type in the interface is String, and in the implementing class is Object.

于 2012-05-14T15:55:11.450 回答
2

这种行为背后的原理称为协变返回类型。在这种特殊情况下,覆盖类型可能会“缩小”最初声明的参数类型。

这意味着 asString是子类化ObjectObject可以被String.

于 2012-05-14T15:57:28.603 回答
1

string 类继承自 object 类,所以只有这段代码有效。

于 2012-05-14T15:59:26.030 回答
1

第一个示例不起作用而第二个示例起作用的原因是因为函数原型仅由名称和所有参数定义,而不是返回类型。在第一个示例中,存在差异,因此编译器认为它们是两个不同的函数。

在第二个例子中,实现的函数并没有扩展类型,而是特化了类型(String 是 Object 的特化),所以它可以工作。

同样,您可以限制已实现方法的可见性,但不能扩大它。

此外,Java 有泛型,在这种情况下很有用。

例子:

interface I<T>
{
    public void doSomething(T x);
}

class MyType implements I<String>
{
    public void doSomething(String x)
    {
        System.out.println(x);
    }
}
于 2012-05-14T15:55:26.483 回答
1

方法签名不考虑返回类型。(虽然声明两个具有相同签名但返回类型不同的方法是错误的)。所以:

void doSomething(Object)
void doSomething(String)

只是两个方法,没有一个覆盖或实现另一个

于 2012-05-14T15:55:47.503 回答