定义

在子类中如果创建了一个与父类中相同名称、相同返回值类型、相同参数列表的方法,只是方法体中的实现不同,以实现不同于父类的功能,这种方式被称为方法重写(override),又称为方法覆盖。当父类中的方法无法满足子类需求或子类具有特有功能的时候,需要方法重写。

子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。

要求

在重写方法时,需要遵循下面的规则:

  • 参数列表必须完全与被重写的方法参数列表相同。
  • 返回的类型必须与被重写的方法的返回类型相同(Java1.5 版本之前返回值类型必须一样,之后的 Java 版本放宽了限制,返回值类型必须小于或者等于父类方法的返回值类型)。
  • 访问权限不能比父类中被重写方法的访问权限更低(public > protected > default > private)。
  • 重写方法一定不能抛出新的检査异常或者比被重写方法声明更加宽泛的检査型异常。例如,父类的一个方法声明了一个检査异常 IOException,在重写这个方法时就不能抛出 Exception,只能拋出 IOException 的子类异常,可以抛出非检査异常。

另外还要注意以下几条:

  • 重写的方法可以使用 @Override 注解来标识。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够再次声明。
  • 构造方法不能被重写。
  • 子类和父类在同一个包中时,子类可以重写父类的所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中时,子类只能重写父类的声明为 public 和 protected 的非 final 方法。
  • 如果不能继承一个方法,则不能重写这个方法。

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.base.learn;

/**
* 方法重写
*/
class Animal {
public void displayInfo() {
System.out.println("I am an animal.");
}
}

class Dog extends Animal {
@Override
public void displayInfo() {
System.out.println("I am a dog.");
}
}

public class Main {
public static void main(String[] args) {
Dog d1 = new Dog();
d1.displayInfo();
}
}
// I am a dog.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.base.learn;

/**
* 方法重写,从子类访问父类的方法,可以使用 super 关键字
*/
class Animal {
public void displayInfo() {
System.out.println("I am an animal.");
}
}

class Dog extends Animal {
@Override
public void displayInfo() {
super.displayInfo();
System.out.println("I am a dog.");
}
}

public class Main {
public static void main(String[] args) {
Dog d1 = new Dog();
d1.displayInfo();
}
}
// I am an animal.
// I am a dog.

@Override

  • @Override:注解,重写注解校验
  • 这个注解标记的方法,就说明这个方法必须是重写父类的方法,否则编译阶段报错。
  • 建议重写都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!

四种权限修饰符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package com.base.learn2;

/**
* 体会四种权限修饰符,在类内部,都是可以访问
*
*/
public class Order {
private int orderPrivate;
int orderDefault;
protected int orderProtected;
public int orderPublic;

private void methodPrivate() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}

void methodDefault() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}

protected void methodProtected() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}

public void methodPublic() {
orderPrivate = 1;
orderDefault = 2;
orderProtected = 3;
orderPublic = 4;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.base.learn2;

/**
* 同一个包中的其它类
*
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();

// order.orderPrivate = 0; // 同一个包中的其它类,不可调用 Order 类中的私有属性和方法
order.orderDefault = 1;
order.orderProtected = 2;
order.orderPublic = 3;

// order.methodPrivate();
order.methodDefault();
order.methodProtected();
order.methodPublic();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.base.learn3;

import com.base.learn2.Order;

/**
* 在不同包的子类调用
*
*/
public class SubOrder extends Order {
public void method() {

orderProtected = 2;
orderPublic = 3;

methodProtected();
methodPublic();

// 在不同包的子类中,不能调用 Order 类中声明为 private 和 缺省权限的属性和方法
// orderPrivate = 0;
// orderDefault = 1;
// methodPrivate();
// methodDefault();

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.base.learn3;

import com.base.learn2.Order;

/**
* 不同包的普通类
*
*/
public class OrderTest {
public static void main(String[] args) {
Order order = new Order();
order.orderPublic = 1;
order.methodPublic();

// 不同包下的普通类(非子类)要使用 Order 类,不可以调用声明为 private、缺省、protected 权限的属性、方法。
// order.orderPrivate = 2;
// order.orderProtected = 3;
// order.orderProtected = 4;

// order.methodPrivate();
// order.methodDefault();
// order.methodProtected();
}
}

重载和重写区别

  • 定义不同:重载是定义相同的方法名、参数不同,重写是子类重写父类的方法
  • 范围不同:重载是在一个类中,重写是子类与父类之间的
  • 多态不同:重载是编译时的多态性,重写是运行时的多态性
  • 参数不同:重载的参数个数、参数类型、参数的顺序可以不同,重写父类子方法参数必须相同
  • 修饰不同:重载对修饰范围没有要求,重写要求重写方法的修饰范围大于被重写方法的修饰范围

多态是一个类需要表现出多种形态,子类重写父类的方法,使子类具有不同的方法实现