Skip to content

重写规则

方法重写看似简单——子类覆盖父类方法。但 Java 定义了一套严格的规则,违反任何一条都会导致编译错误。面试中也经常考察这些细节。

规则一览

规则具体要求
方法名必须与父类相同
参数列表必须与父类完全相同(类型和个数)
返回类型可以是父类返回类型的子类型(协变返回)
访问修饰符不能比父类更严格
异常声明不能抛出新的或更宽的受检异常

代码示例

基本规则

java
public class OverrideRulesDemo {

    static class Parent {
        Object method(String s) {
            System.out.println("Parent method");
            return null;
        }
    }

    static class Child extends Parent {
        // ✅ 重写:返回类型 String 是 Object 的子类型(协变返回)
        @Override
        String method(String s) {
            System.out.println("Child method");
            return "result";
        }
    }
}

访问修饰符

访问权限只能扩大,不能缩小:

java
public class AccessModifierDemo {

    static class Parent {
        protected void display() {
            System.out.println("Parent display");
        }
    }

    static class Child extends Parent {
        // ✅ protected -> protected(相同)
        @Override
        protected void display() {
            System.out.println("Child display");
        }

        // ✅ protected -> public(扩大)
        @Override
        public void anotherMethod() {
            System.out.println("Child another method");
        }

        // ❌ 编译错误:protected -> private(缩小)
        // @Override
        // private void display() {}
    }
}

异常声明

受检异常的范围只能缩小,不能扩大:

java
public class ExceptionRuleDemo {

    static class Parent {
        void method() throws RuntimeException {
            System.out.println("Parent method");
        }
    }

    static class Child extends Parent {
        // ✅ 不抛出异常(缩小)
        @Override
        void method() {
            System.out.println("Child method");
        }

        // ✅ 抛出更具体的异常(缩小)
        @Override
        void anotherMethod() throws ArithmeticException {
            System.out.println("Child another method");
        }

        // ❌ 编译错误:throws Exception(扩大)
        // @Override
        // void method() throws Exception {}
    }
}

静态方法:隐藏而非重写

静态方法不属于对象,没有多态,所以是「隐藏」而非「重写」:

java
public class StaticMethodOverrideDemo {

    static class Parent {
        static void staticMethod() {
            System.out.println("Parent static method");
        }

        void instanceMethod() {
            System.out.println("Parent instance method");
        }
    }

    static class Child extends Parent {
        // ❌ 这不是重写,是隐藏
        static void staticMethod() {
            System.out.println("Child static method");
        }

        @Override
        void instanceMethod() {
            System.out.println("Child instance method");
        }
    }

    public static void main(String[] args) {
        Parent p = new Child();

        // 静态方法:取决于引用类型(Parent),不是实际类型
        p.staticMethod();    // 输出: Parent static method

        // 实例方法:取决于实际类型(Child),这才叫多态
        p.instanceMethod();   // 输出: Child instance method
    }
}

私有方法不能被重写

private 方法对子类不可见,所以子类定义同名方法是一个新的方法,不是重写:

java
public class PrivateMethodDemo {

    static class Parent {
        private void privateMethod() {
            System.out.println("Parent private method");
        }

        public void callPrivate() {
            privateMethod(); // 始终调用父类的版本
        }
    }

    static class Child extends Parent {
        // 这不是重写,是子类自己的新方法
        private void privateMethod() {
            System.out.println("Child private method");
        }
    }

    public static void main(String[] args) {
        Parent p = new Child();
        p.callPrivate(); // 输出: Parent private method
    }
}

@Override 注解的作用

强烈建议始终加上 @Override 注解,它有两个作用:

  1. 编译期检查:如果方法签名写错了,编译器会报错
  2. 代码可读性:明确表示这是重写方法
java
public class OverrideAnnotationDemo {

    static class Parent {
        void method(String s) { }
    }

    static class Child extends Parent {
        // ❌ 编译错误:如果没有 @Override,编译器不会报错
        // 你以为重写了,实际上是新方法
        void method(String s, int i) { }
    }

    static class Child2 extends Parent {
        @Override
        void method(String s) { } // ✅ 正确重写
    }
}

注意事项

  1. 协变返回:JDK 5 引入,子类方法可以返回父类返回类型的子类型
  2. 静态方法:没有重写,只有隐藏,调用时看引用类型
  3. 私有方法:子类不可见,不存在重写一说
  4. final 方法:父类用 final 修饰的方法不能被重写
  5. 构造方法:不能被重写

基于 VitePress 构建