Java 重写(Override)与重载(Overload)
Java 重写 (Override) 与 重载 (Overload) 深度解析在 Java 面试和实际开发中重写 (Override)和重载 (Overload)是最容易混淆的两个概念。它们虽然名字相似但本质、应用场景和规则完全不同。1. 核心区别概览特性重载 (Overload)重写 (Override)发生范围同一个类中父子类之间 (继承关系)方法名必须相同必须相同参数列表必须不同(个数、类型、顺序)必须完全相同返回类型可以不同必须相同 (或是其子类)访问权限可以不同不能比父类更严格 (只能更宽或相同)异常处理可以不同不能抛出比父类更多/更宽的异常静态方法可以重载不能重写 (静态方法是隐藏)绑定方式静态绑定(编译时确定)动态绑定(运行时确定多态基础)核心目的提供多种输入方式提高可读性改变父类行为实现多态2. 重载 (Overload) - 编译时多态2.1 定义在同一个类中方法名相同但参数列表不同参数类型、个数或顺序不同的一组方法。2.2 规则详解参数列表必须不同void show(int a)和void show(String a)✅ (类型不同)void show(int a)和void show(int a, int b)✅ (个数不同)void show(int a)和void show(int b)❌ (参数名不同不算编译器只看类型和个数)返回类型无关仅返回类型不同不能构成重载。int show()和String show()❌ (编译报错方法已定义)访问修饰符和异常可以随意修改不影响重载判定。2.3 代码示例publicclassCalculator{// 加法两个整数publicintadd(inta,intb){returnab;}// 加法三个整数 (参数个数不同)publicintadd(inta,intb,intc){returnabc;}// 加法两个浮点数 (参数类型不同)publicdoubleadd(doublea,doubleb){returnab;}// 错误示例仅返回类型不同不是重载// public String add(int a, int b) { return ; } // 编译错误!}2.4 应用场景构造方法提供多种初始化方式。工具类如System.out.println()可以打印 int, double, String 等。提高代码可读性让方法名语义统一通过参数区分逻辑。3. 重写 (Override) - 运行时多态3.1 定义在子类中重新定义父类中已有的方法。方法名、参数列表、返回类型必须一致。3.2 规则详解 (黄金法则)三同原则方法名相同。参数列表完全相同。返回类型相同或为父类返回类型的子类即协变返回类型。访问权限子类方法的访问权限父类方法。例如父类是protected子类可以是protected或public但不能是private或 default。异常限制子类抛出的异常类型父类抛出的异常类型。子类可以抛出更具体的异常或者不抛出异常但不能抛出父类未声明的受检异常。静态方法静态方法不能被重写。如果子类定义了同名的静态方法这叫方法隐藏 (Hiding)调用时取决于引用变量的类型而非对象类型。私有方法私有方法不能被继承因此也不能被重写。3.3 代码示例classAnimal{publicvoideat(){System.out.println(动物在吃东西);}// 协变返回类型示例 (Java 5)publicAnimalcreate(){returnnewAnimal();}}classDogextendsAnimal{Override// 推荐编译器检查防止写错publicvoideat(){System.out.println(狗在吃骨头);}// 协变返回类型返回类型是父类返回类型的子类OverridepublicDogcreate(){returnnewDog();}// 错误示例访问权限降低// private void eat() { ... } // 编译错误!// 错误示例抛出更多异常// public void eat() throws IOException { ... } // 编译错误!}3.4 应用场景多态父类引用指向子类对象调用重写方法时执行子类逻辑。框架扩展如 Spring 的Override生命周期方法JDBC 的ResultSet处理等。4. 深度对比静态绑定 vs 动态绑定这是理解两者的关键4.1 重载 (Overload) - 静态绑定 (Static Binding)时间在编译期确定调用哪个方法。依据编译器根据引用变量的声明类型和传递参数的类型来决定。演示classParent{}classChildextendsParent{}classTest{voidshow(Parentp){System.out.println(Parent);}voidshow(Childc){System.out.println(Child);}}publicstaticvoidmain(String[]args){ParentpnewChild();TesttnewTest();t.show(p);// 输出 Parent// 虽然 p 实际指向 Child 对象但编译器只看 p 的声明类型是 Parent}4.2 重写 (Override) - 动态绑定 (Dynamic Binding)时间在运行期确定调用哪个方法。依据JVM 根据对象的实际类型来决定。演示classParent{voidshow(){System.out.println(Parent);}}classChildextendsParent{Overridevoidshow(){System.out.println(Child);}}publicstaticvoidmain(String[]args){ParentpnewChild();p.show();// 输出 Child// 编译器看到 p 是 Parent 类型允许调用 show()// 运行时 JVM 发现 p 指向的是 Child 对象调用 Child 的 show()}5. 常见陷阱与面试题Q1: 构造方法可以重载吗可以重写吗可以重载同一个类中可以有多个构造方法参数不同。不能重写构造方法不能被继承所以子类无法重写父类构造方法。Q2:static方法可以重写吗不能。static方法属于类不属于对象。子类定义同名静态方法叫隐藏。陷阱classA{staticvoidprint(){System.out.println(A);}}classBextendsA{staticvoidprint(){System.out.println(B);}}AanewB();a.print();// 输出 A (静态绑定看引用类型 A)Q3:final方法可以重写吗不能。final修饰的方法禁止被子类重写。Q4: 重载时参数类型是基本类型和包装类怎么匹配Java 会自动进行自动拆箱/装箱和类型提升。优先级精确匹配 自动装箱 类型提升。voidtest(inti){}voidtest(Integeri){}test(1);// 调用 test(int)test(1.0);// 报错double 不能自动转为 int 或 IntegerQ5: 如何区分重载和重写看位置同一个类 重载父子类 重写。看参数参数不同 重载参数相同 重写。看多态涉及运行时多态 重写编译时确定 重载。6. 总结口诀重载同个类名同参异编译定静态绑。重写父子类名同参同运行定动态绑。权限重写不能更严格异常不能更宽泛。静态静态方法不能重只能隐藏看引用。