java方法覆盖的一点研究
对于方法覆盖,本来我的理解是:子类覆盖父类的方法,当子类的方法签名与父类一致时,就算覆盖了父类的方法。然而在研究String相关类源码是发现了这样的代码:
/**
* AbstractStringBuilder是StringBuilder和StringBuffer的抽象父类。
*AbstractStringBuilder类append()方法
*/
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
/**
* StringBuilder类的append()方法
*/
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
猛一看没什么问题,方法名相同,入参一致,子类中还调用的父类的方法,子类确实是覆盖子类了。可是等等,它们的返回值类型居然不一致。
JDK的代码怎么会有问题,我在本地写了两个类,同样的方式,也可以。然后我就猜测,应该是子类的返回类型正好是父类方法返回类型的子类(这个例子的确有点特殊,返回值正好是本身),于是我又做了个实验:
//创建了两个空类,测试用
public class Foo {
}
class Bar extends Foo{
}
/**
* People作为父类,定义了一个方法
*/
public class TestPeople {
Foo test(Foo f){
return new Foo();
}
}
public class TestStudent extends TestPeople {
/**
* 注意返回值为Bar,父类中返回值为Foo,说明子类返回值类型为父类返回值的子类型也可
* @param foo
* @return
*/
@Override //强制加覆盖注解为测试是否真正覆盖了父类方法
Bar test(Foo foo) {
return new Bar();
}
}
好了,现在验证了我们的猜想,当子类覆盖父类方法时,子类返回值可以是父类方法返回值类型或其子类型。那我们不禁想,那传入参数呢,是否也符合?很遗憾,经测试时不行的,TestPeople不变,TestStudent 如下:
public class TestStudent extends TestPeople {
/**
* 当入参改为Bar类型时,编译报错了
* @param foo
* @return
*/
@Override //此处报错了 method does not override from its supperclass
Bar test(Bar foo) {
return new Bar();
}
}
综上, 子类覆盖父类方法时:
1. 方法名及入参数类型必须保持一致.
2. 返回值类型需保持是父类返回值的类型或其子类型
另外还有2点也是需记住的:
3. 覆盖的不能是私有方法(这个好理解,私有的外部类也不可见)
4. 子类方法抛出的异常需是父类异常类型或其子类型(同返回值一样的限制)