只是玩弄界面,我对我无法理解的事情有疑问。
以下代码无法运行,这是我期望的行为,因为接口方法要求该方法适用于任何对象,并且实现的方法将签名更改为仅允许字符串对象。
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);
}
}
答案 0 :(得分:3)
public Object doSomething(String x);
必须返回一些东西。事实上,任何东西,只要它是某种类型的对象。所以,如果你实施
public String doSomething(String x) {stuff}
没关系,因为它确实会返回一个Object。它将返回的对象永远是一个字符串这一事实没什么大不了的。
第一个例子不起作用的原因是因为仅接受字符串比接受任何对象更具限制性。但只返回字符串就好了。
作为一个类比,假设你得到了一个建筑物的合同,你会聘请一些员工来帮助你。合同要求您雇用任何适用的画家,无论他们有多高,但没有指定使用什么颜色的颜料。如果您只雇用超过6英尺高的画家(这是输入,只接受字符串而不是所有对象),那么您将违反合同。但是选择只涂上蓝色油漆(只返回字符串)就好了,因为合同没有指定颜色,只有你必须要涂漆。
答案 1 :(得分:2)
它有效,因为String
是Object
。
答案 2 :(得分:2)
来自java语言规范:
如果返回类型是引用类型,则返回类型可能会因覆盖彼此的方法而异。返回类型可替代性的概念支持协变返回,即返回类型到子类型的特化。
所以换句话说,它就像你一样工作,但是如果接口中的返回类型是String,并且在实现类中是Object,它将不起作用。
答案 3 :(得分:2)
此行为背后的原理称为covariant return type。在这种特殊情况下,覆盖类型可以“缩小”最初声明的参数类型。
这意味着由于String
是子类Object
,Object
可能会被String
取代。
答案 4 :(得分:2)
这与Java SE 5.0中引入的协变返回类型有关。
您可以在http://docs.oracle.com/javase/tutorial/java/javaOO/returnvalue.html
答案 5 :(得分: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);
}
}
答案 6 :(得分:1)
方法签名不考虑返回类型。 (虽然声明两个具有相同签名但返回类型不同的方法是错误的)。所以:
void doSomething(Object)
void doSomething(String)
只是两个方法而没有覆盖或实现另一个
答案 7 :(得分:1)
字符串类继承自对象类,因此只有此代码才有效。