重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。
重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。
重写父类中的方法
概念
当一个子类中一个实例方法具有与其父类中的一个实例方法相同的签名(指名称、参数个数和类型)和返回值时,称子类中的方法“重写”了父类的方法。例如
class A{
public void sayHello() { //输出英文欢迎
System.out.println("Hello!");
}
public void sayBye() {
System.out.println("GoodByene");
}
}
class B extends A {
public void sayHello() { //输出中文欢迎
System.out.println("Hello world!!!");
}
}
public class myfirst {
public static void main(String[] args) {
B b=new B(); //创建子类B的一个实例对象,使用默认构造方法
b.sayHello(); //调用子类中重写的方法
b.sayBye(); //调用父类中的方法
}
重写规则
参数列表与被重写方法的参数列表必须完全相同。
返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
父类的成员方法只能被它的子类重写。
声明为
final
的方法不能被重写。声明为
static
的方法不能被重写,但是能够被再次声明。子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为
private
和final
的方法。子类和父类不在同一个包中,那么子类只能够重写父类的声明为
public
和protected
的非fina
l 方法。重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
构造方法不能被重写。
如果不能继承一个类,则不能重写该类的方法。
- 子类可以通过
super()
访问被重写的父类中的方法
class A{ public void sayHello() { //输出英文欢迎 System.out.println("Hello!"); } } class B extends A { public void sayHello() { super.sayhello() //输出中文欢迎 System.out.println("Hello world!!!"); } } public class Test { public static void main(String[] args) { B b=new B(); //创建子类B的一个实例对象,使用默认构造方法 b.sayHello(); //调用子类中重写的方法 }
隐藏父类中的方法
如果一个子类定义了一个静态类方法,而这个类方法与其父类的一个类方法具有相同的签名(指名称、参数格式和类型)和返回值,则称在子类中的这个类方法“隐藏”了父类中的该类方法。
- 当调用被重写的方法时,调用的版本是子类的方法;
- 当调用被隐藏的方法时,调用的版本取决于是从父类中调用还是从子类中调用。
下面有一个例子(取材于该博客),我暂时还没看懂,先挂一下...
//原文链接:https://blog.csdn.net/weixin_52122271/article/details/114285424
class A{
public static void sayHello() { //静态类方法
System.out.println("大家好,这是A的静态类方法");
}
public void sayHello2() { //实例方法
System.out.println("大家好,这是A中的实例方法");
}
}
class B extends A {
public static void sayHello() { //静态类方法
System.out.println("大家好,这是B的静态类方法");
}
public void sayHello2() { //实例方法
System.out.println("大家好,这是B的实例方法");
}
}
public class myfirst {
public static void main(String[] args) {
B b=new B(); //创建B类的实例对象b
A a=b; //隐式对象类型转换
A.sayHello(); //调用A类的静态类方法
a.sayHello(); //调用a对象的静态类方法
B.sayHello(); //调用B类的静态方法
a.sayHello2(); //调用a对象的实例方法
b.sayHello2(); //调用b对象的的实例方法
A a2=new A(); //创建A类的实例对象a2
a2.sayHello2(); //调用a2对象的实现方法
}
/*运行结果
大家好,这是A的静态类方法
大家好,这是A的静态类方法
大家好,这是B的静态类方法
大家好,这是B的实例方法
大家好,这是B的实例方法
大家好,这是A中的实例方法
*/
覆盖父类的中的变量
如果子类中重新定义了一个与父类中已有变量同名的变量,那么父类中的变量就被“覆盖”。
public class Animal{
public String name = "Name";
}
public class Cat extends Animal{
public String name = "Cat";
}
public class Test{
public static void main(String[] args){
Cat cat = new Cat();
System.out.println(cat.name);
}
}
/*运行结果:cat*/
关于@Override
@Override
是伪代码,表示重写,在“子类重写父类”或“某类实现某接口”时使用。写上有如下好处:(详见该博客)
- 可以当注释用,方便阅读;
- 编译器可以给你验证
@Override
下面的方法名是否是你父类中所有的,如果没有则报错。
例如,你如果没写@Override
,而你下面的方法名又写错了,这时你的编译器是可以编译通过的,因为编译器以为这个方法是你的子类中自己增加的方法。