2

为什么允许在子类中更改抽象方法的返回类型?

abstract class Animal {
    public abstract Animal assing(Animal a);
}

class Lizard extends Animal {
    @Override
    public Lizard assing(Animal a) {
        return new Lizard();
    }
}

class Chicken extends Animal {
    @Override
    public Chicken assing(Animal a) {
        return new Chicken();
    }
}

而不允许更改参数类型:

abstract class Animal {
    public abstract void foo(int x);
}

class Lizard extends Animal {
    // compiler error
    // the type Lizard must implement the inherited abstract method Animal.foo(int)
    public void foo(float x) {
    }
}

class Chicken extends Animal {
    @Override
    public void foo(int x) {
    }
}
4

5 回答 5

10

因为,overriden methods允许从java 1.5+ 版本获得协变返回

另外,当您更改具体类中的参数类型时,您基本上是在声明一个全新的方法,该方法与抽象类中定义的抽象方法不同。请记住,您需要(由编译器强制)在扩展抽象类的具体类中实现/覆盖那些抽象方法。

简单地说,这里是java中重写方法的规则:

  • 重写的方法和参数列表应该完全相同
  • 返回类型应该是在超类中被覆盖的原始方法中声明的子类型(在协变返回的情况下),或者应该是相同的。
  • 与覆盖方法的访问级别相比,访问级别的限制并不多。例如,当超类被认为是公共的时,在这种情况下,子类中存在的覆盖方法将不是公共的或私有的。但是与覆盖方法的访问级别相比,访问级别可能没有太大限制。
  • 如果实例方法被子类继承,在这种情况下,只有它们可能被覆盖。
  • 已声明为 final 的方法可能不会被覆盖。
于 2013-03-14T09:26:09.013 回答
1

在您的问题中,您混淆了两个方面:在覆盖方法中使用子类型和在方法参数中使用完全不相关的类型和原语。

在任何情况下,您都不能将 a 从被覆盖的方法更改int为覆盖方法float中的 a。唯一允许的特殊情况是返回类型协方差。从理论上讲,参数类型可以是逆变的,但这会使方法重载解析变得一团糟,这已经非常复杂了。

于 2013-03-14T09:30:16.543 回答
1

被覆盖的方法应该具有相同数量的方法参数并且它们的类型应该相同。但是他们被允许有协变回报

于 2013-03-14T09:33:16.287 回答
0

换一种说法:返回抽象方法所需子类型的方法仍然履行合同。虽然采用浮点数的方法不履行该方法采用 int 的约定。

于 2013-03-14T09:28:24.483 回答
0

协变返回,意味着当一个方法被重写时,被重写方法的返回类型被允许是被重写方法的返回类型的子类型。为了用一个例子来说明这一点,一个常见的例子是 Object.clone() - 它被声明为返回一个 Object 类型。您可以在自己的课程中覆盖它。

于 2013-03-14T09:30:31.567 回答