重写规则

  1. 重写方法的形参必须与被重写的父类方法的形参完全相同。
  2. 重写方法的返回的类型必须一直与被重写的方法的返回类型相同或其子类。
  3. 重写方法的访问修饰符的限制一定要大于被重写方法的访问修饰符。
  4. 重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。

理解

个人认为这四条规则都为了服务于多态:父类引用可以接收子类对象,而子类对象拥有父类对象全部的行为(继承),只不过实现不同(重写)。
回到规则:

1.重写方法的形参必须与被重写的父类方法的形参完全相同。

形参完全相同,反推,如果子类重写的方法形参与被重写方法的形参不相同,当父类引用去接收一个子类对象,运行时,使用父类引用调用被重写方法时,就无法与子类重写方法相匹配,从而无法实现多态。

public class Test{
    
    public void a(Object o) {
       System.out.println("父类方法");
    }
}

public class Test2 extends Test{

    public void a(Integer i){
        System.out.println("子类方法");
    }

	
    public static void main(String[] args) {
        Test test=new Test2();
        Object o=new Object();
        //因为是父类引用,a方法入参只能是Object对象
        test.a(o);
        //即便传入Integer类型,为了防止二义性,也只会被当作Object对象执行父类方法
		Integer integer = 1;
        test.a(integer);
    }
    
}

输出结果

父类方法
父类方法

2.重写方法的返回的类型必须一直与被重写的方法的返回类型相同或其子类。

类型相同好理解,重写方法的返回类型可以是被重写方法返回类型的子类,因为父类引用可以接收子类对象,所以即便返回对象是子类,一样不影响多态特性的使用,也不会产生二义性。

public class Test{

    public Object a(Object o) {
        System.out.println("父类方法");
        return null;
    }
}

public class Test2 extends Test{

    public static void main(String[] args) {
        Test test=new Test2();
        Object o=new Object();
        //使用被重写方法的返回类型Object接收重写方法的返回值
        Object integer = test.a(o);
        System.out.println(integer);
    }
    
    @Override
    public Integer a(Object o){
        System.out.println("子类方法");
        return 1;
    }
}

输出结果

子类方法
1

3.重写方法的访问修饰符的限制一定要大于被重写方法的访问修饰符。
4.重写方法不能抛出新的异常或者比被重写方法声明的检查异常更广的检查异常。但是可以抛出更少,更有限或者不抛出异常。

3、4两点同理,都是为了保证用父类引用接收子类对象时,使用父类引用不会出现错误。