在研究重写问题之前先看一下什么是方法签名?
方法签名由方法名称和一个参数列表(方法的参数的顺序和类型)组成。
注意,方法签名不包括方法的返回类型。不包括返回值和访问修饰符。
方法重写
“方法的签名” 与父类一模一样,并且在父子类之间出现方法签名一致, 这个叫重写/覆盖
编译时。子类必须能看见父类的方法,所以父类方法可重写的条件不能被 private 修饰。
重写的规范
在方法前加上@Override, 编译器会帮你做重写检查
先说下返回值问题
子类返回值[层次] <= 父类返回值[层次]
在李阳的Java疯狂讲义中说重写返回值类型要比父类小,什么叫比父类小,即使实现或者继承了该类的类,经过查阅相关资料得出下面结论
Java 5或者以前,必须一样,java 7 java 8可以不同,但是必须是父类返回值的派生类。
再说下访问修饰符
修饰符: 子类权限 >= 父类权限
Java中访问修饰符的范围大小 public > protected > default > private,子类重写父类的方法的访问修饰符,不能低于父类的方法访问权限;
结合例子说明一下,代码是在JDK1.8的环境下编辑的。
类之间的逻辑关系也很简单
- Child 继承自 Father 类,目的是重写 Father 里面的方法。
- Vegetable 继承自 Food 类并实现了 Healthy 接口。目的是测试重写方法的返回值和权限修饰符规则。
贴下代码:
public class Father {
protected Food protectedLoad() {
return null;
}
protected Healthy protectedLoadInterface() {
return null;
}
}
在 Father 类中定义了两个方法
- protectedLoad: 修饰符为 protected ,返回值为 Food 类。
- protectedLoadInterface: 修饰符为 protected,返回值为 Healthy 接口。
public class Chlid extends Father{
@Override
public Vegetable protectedLoad() {
return null;
}
@Override
protected Vegetable protectedLoadInterface() {
return null;
}
}
在继承自 Father 的 Chlid 类中,分别对 protectedLoad 和 protectedLoadInterface 方法实现了重写。可以看到
- protectedLoad: 修饰符拓展为了 public ,返回值为 Food 类的子类 Vegetable。
- protectedLoadInterface: 修饰符为 protected ,未做修改,返回值为 Healthy 接口的实现类 Vegetable。
所以,经过实践可以很清楚的得出我们上面的结论
- 重写方法返回值类型要比父类小。
- 重写方法的访问修饰符不能低于父类的方法访问权限。
另外三个辅助类
public class Food {
}
public interface Healthy {
}
public class Vegetable extends Food implements Healthy{
}
这里再说一下题外话,关于方法重载的问题
方法的重载:
判定一个方法是否属于重载或重复定义是根据方法的签名来定。
所以主要你的方法名和参数列表相同,编辑器就会判断两个方法为同一个方法。咱们继续使用 Father 类的例子,如下,定义两个相同方法名和参数列表的 getFood 方法。
public class Father {
protected Food protectedLoad() {
return null;
}
protected Healthy protectedLoadInterface() {
return null;
}
private Food getFood(int num) {
return new Food();
}
//这里会在Idea中报错,提示 getFood(int) is already defined in Father
private int getFood(int num) {
return num;
}
}
在上面的例子中,编译器直接爆出 getFood(int) is already defined in Father 的错误,所以关于方法重载
的问题,只与方法的签名相关和方法的返回值无关,签名相同会被编辑器认为是同一个方法。