可协变的返回类型(Covariant return types )
可协变的返回类型 :允许子类将覆盖方法的返回类型定义为原返回类型的子类型。
在Java 1.5 之前,在覆盖一个方法时,子类方法的方法名,参数类型和返回类型必须和超类的被覆盖方法完全一致,不允许改变被覆盖方法的返回类型。但是现在,Java 1.5 之后,子类在覆盖返回类型不是基本类型的方法时,允许将返回类型改为原类型的子类型。
如何实现的
先看一个例子
class B {
public B foo() {
...
return new B();
}
}
class C extends B {
@Override
public C foo() {
...
return new C();
}
}
public static void main(String[] args) {
Class<?> cls = C.class;
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) {
System.out.println(m + (m.isSynthetic() ? " isSynthetic" : " noSynthetic") + (m.isBridge() ? " isBridge" : " noBridge"));
}
}
// 输出
public reflectionTest.C reflectionTest.C.foo() noSynthetic noBridge
public reflectionTest.B reflectionTest.C.foo() isSynthetic isBridge
通过反射我们发现类C中出了方法 public C foo() ,还有方法 public Bfoo(),并且方法 public B foo() 是合成的桥方法。为什么类C能有两个方法名称相同并且参数类型也相同的方法呢?
尽管在Java 中,方法的签名只包括方法名称和方法的参数类型,不允许基于返回类型的方法重载(即,方法名称和类型参数都相同,方法返回类型不同)。但是在JVM是允许基于返回类型的方法重载的,JVM通过方法的参数类型和返回类型进行方法调用(区分不同方法)。所以在JVM中,一个类可以拥有多个仅仅是返回类型不同的方法。
为了实现可协变的返回类型,Java会隐式合成新的方法。
实际上javac生成的代码类似于这样:
class C extends B{
public C foo() {
// your code from the source file
}
// javac generated method in the .class file
public B foo() {
// 调用另一个foo()方法
}
}