5.4 方法重写
- 参考书籍:Java面向对象程序设计(第二版)--耿祥义 张跃平编著
- 定义
子类通过重写(Override)可以隐藏已继承的实例方法(方法重写也称为方法覆盖)
- 规则
1:子类和父类的方法的类型一致
2:父类的方法的类型的子类型,方法名字,参数个数,参数类型和父类方法一致
3:重写方法可以操作继承的成员变量,也可以操作子类新声明的成员变量
4:用super使用隐藏的方法
- 如果子类可以继承父类的某个实例方法,那么子类就有权利重写这个方法
- 目的
通过方法的重写可以隐藏继承的方法,子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为
问题来了(如果解释有错误请纠正)
A类
package packlx3;
class A {
double f(float x,float y){
return x+y;
}
}
B类
package packlx3;
class B extends A{
double f(float x,float y,float z){ //问题,这样是重写吗,可以编译成功吗,如果不是重写那又是什么???????
return x*y*z;
}
}
主类
package packlx3;
public class Lianxi3 {
public static void main(String args[]){
B b=new B();
double d=b.f(2, 4, 3);
System.out.println(d);
}
}
个人解答:首先,重写是要求方法名字,参数个数,参数类型和父类方法一致的,由此可见float z是多的,那么应该是编译失败才对
可是编译却成功,编辑结果为24.0
这时候我想到了重载(此处不详细讲),就是:
可以将重载分为在一个类中重载,和在子类和父类中重载。
解释如下:
1.在一个类中定义多个名字相同的方法,这些方法必须具有不同的参数列表,比如一个类的构造函数。
2.在父类和子类中,子类继承而拥有了父类的某些方法,此时在子类再定义具有相同名字的方法(必须具有不同的参数列表)。
由此可以得到结论:这样不是重写,而是重载,可以编译
- JDK1.5对重写的改进
在JDK1.5版本之后,允许重写方法的类型是父类方法的类型的子类型,即不必完全一致(JDK1.5版本之前要求必须一致)
People类
package packlx4;
public class People {
public void speak(){
System.out.println("我是People");
}
}
Chinese类
package packlx4;
public class Chinese extends People{
public void speak(){
System.out.println("我是中国人"); //方法名字,参数个数,参数类型一致,重写
}
}
主类
package packlx4;
class CreatePeople{
public People creatPeople(){ //方法类型是People类 为什么可以拿People作为类型呢
People p= new People(); //因为类是面向对象语言中最重要的一种数据类型,类声明的变量称为对象
return p;
}
}
class CreateChinese extends CreatePeople{ //继承
public Chinese createPeople(){ //重写方法的类型是People类的子类Chinese,即子类型
Chinese chinese=new Chinese();
return chinese;
}//重点:如果父类的方法的类型是“类”,即父类CreatPeople的方法creatPeople的类型是People类,那么重写方法的类型可以是“子类”
} //即子类CreateChinese的方法createPeople的类型是chinese,而chinese是People的子类
public class Lianxi4 {
public static void main(String args[]){
CreateChinese create=new CreateChinese(); //子类CreateChinese声明对象create
Chinese zhang=create.createPeople(); //Chinese 对象=chinese(返回的值)
zhang.speak();
}
}
- 重写还要注意事项
(1)重写父类方法时,不可以降低方法的访问权限
Public>protected>友好>private
(2)返回类型必须与被重写方法的返回类型相同。
父类方法A:
void p(){
}
子类方法B:
int p(){
}
参数相同,返回类型不同,不是重写。
父类方法A:
int p(){
}
子类方法B:
long p(){
}
返回类型虽然兼容父类,但是不同,不是重写。
(3)重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。
注意:这种限制只是针对检查异常,至于运行时异常RuntimeException及其子类不再这个限制之中。
(4)不能重写被标识为final的方法
(5)如果一个方法不能被继承,则不能重写它。如private方法,比如父类的private方法
package packlx5;
class A{ //父类A
private void a(){ //权限私有
System.out.println("我是Aa");
}
}
class B extends A{ //子类B继承A
public void a(){ //提高权限,变为公有
System.out.println("我是Ba");
}
}
public class Lianxi5 {
public static void main(String grgs[]){
B b=new B();
//A b=new B(); //把子类B的引用放到父类a中,这时候b是一个上转型对象,
b.a();
}
}
但是这里可以编译成功,输出我是Ba,难道规则错误???
其实这里是一个巧合,A类的a()方法不能被继承因此B类中的a()方法是一个新的方法,不是重写也不是重载,只是一个只属于B类的全新的方法!
如果你把主类中的B b=new B();改为A b=new B();则会出现错误,因为对象的上转型对象只能操作继承或者隐藏的变量或方法,多态只看父类引用的方法,而不看子类对象的方法!
- 子类不能用 静态方法 重写 父类的非静态方法
- 子类不能用 非静态方法 重写 父类的静态方法
(6)(7)留待思考