java
主页 > 软件编程 > java >

Java方法重载与重写之同名方法的双面魔法(最新整理)

2025-12-05 | 佚名 | 点击:

Java方法重载与重写:同名方法的双面魔法

各位道友们好!今天咱们来聊聊Java中两个容易混淆的概念:方法重载(Overloading)和方法重写(Overriding)。这俩兄弟长得像,但性格完全不同,就像吕洞宾的剑法——看似相似,实则各有千秋!

方法重载(Overloading):同门师兄弟的不同绝技

什么是方法重载?

方法重载就像是一个门派里的师兄弟,虽然名字相同(方法名相同),但各有各的独门绝技(参数列表不同)。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

class KungFuMaster {

    // 基础招式

    public void attack() {

        System.out.println("普通拳法!");

    }

    // 重载版本1:带武器

    public void attack(String weapon) {

        System.out.println("使用" + weapon + "攻击!");

    }

    // 重载版本2:带武器和力量

    public void attack(String weapon, int power) {

        System.out.println("使用" + weapon + "发动" + power + "成功力!");

    }

    // 重载版本3:不同参数顺序

    public void attack(int power, String weapon) {

        System.out.println(power + "成功力施展" + weapon + "!");

    }

}

重载的核心特征

必要条件:

调用示例:

1

2

3

4

5

KungFuMaster master = new KungFuMaster();

master.attack();                    // 普通拳法!

master.attack("宝剑");              // 使用宝剑攻击!

master.attack("宝剑", 8);           // 使用宝剑发动8成功力!

master.attack(8, "宝剑");           // 8成功力施展宝剑!

重载的优点

  1. 提高代码可读性:相同功能的方法使用相同名字
  2. 简化API设计:用户只需要记住一个方法名
  3. 灵活性强:支持多种参数组合

重载的陷阱和反例

反例1:仅靠返回类型不同不能重载

1

2

3

4

5

class ErrorExample {

    public void show() { }

    public int show() { return 1; } // 编译错误!

}

// 原因:编译器无法区分调用哪个方法,只看方法名和参数列表

反例2:参数列表必须真正不同

1

2

3

4

5

class ErrorExample2 {

    public void train(String student) { }

    public void train(String master) { } // 编译错误!

}

// 原因:参数名不同不算重载,要看参数类型

方法重写(Overriding):子承父业的技艺传承

什么是方法重写?

方法重写就像是儿子继承父亲的手艺,但青出于蓝而胜于蓝——方法签名相同,但实现更优秀。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// 父类:老拳师

class OldMaster {

    public void secretMove() {

        System.out.println("老式绝招:降龙十八掌");

    }

    public final void forbiddenMove() {

        System.out.println("禁招:不得传授");

    }

}

// 子类:新拳师

class NewMaster extends OldMaster {

    @Override

    public void secretMove() {

        System.out.println("新式绝招:升级版降龙十八掌");

    }

    // 不能重写final方法

    // @Override

    // public void forbiddenMove() { } // 编译错误!

}

重写的核心规则

必要条件:

@Override注解的重要性:

1

2

3

4

5

6

7

8

9

10

class SmartMaster extends OldMaster {

    @Override  // 加上这个注解更安全

    public void secretMove() {

        System.out.println("智能绝招");

    }

    // 如果没有@Override,拼写错误不会被发现

    public void secretmove() { // 本想重写,但方法名写错了

        System.out.println("这其实是个新方法,不是重写!");

    }

}

重写的优点

  1. 实现多态:运行时根据实际对象类型调用方法
  2. 扩展性强:子类可以改进或扩展父类行为
  3. 符合开闭原则:对扩展开放,对修改关闭

重载 vs 重写:终极对决

对比表格

特性 方法重载 (Overloading) 方法重写 (Overriding)
发生位置 同一个类中 父子类之间
方法签名 必须不同 必须相同
返回类型 可以不同 必须相同或协变
访问权限 可以不同 不能更严格
绑定时机 编译时绑定 运行时绑定
多态性 不支持多态 支持多态

实际代码对比

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

class Animal {

    // 重载示例

    public void eat() {

        System.out.println("动物吃东西");

    }

    public void eat(String food) {

        System.out.println("动物吃" + food);

    }

    // 可重写的方法

    public void sleep() {

        System.out.println("动物睡觉");

    }

}

class Dog extends Animal {

    // 重写父类方法

    @Override

    public void sleep() {

        System.out.println("狗狗趴着睡觉");

    }

    // 重载:新增方法

    public void eat(String food, int amount) {

        System.out.println("狗狗吃" + amount + "份" + food);

    }

}

深入理解:协变返回类型

Java 5的新特性

协变返回类型允许重写方法时返回父类方法返回类型的子类型:

1

2

3

4

5

6

7

8

9

10

11

class Fruit {

    public Fruit getFruit() {

        return new Fruit();

    }

}

class Apple extends Fruit {

    @Override

    public Apple getFruit() { // 返回Apple而不是Fruit

        return new Apple();

    }

}

反例:Java 5之前的问题

1

2

3

4

5

6

7

8

9

// Java 5之前的写法(需要强制转型)

class OldApple extends Fruit {

    @Override

    public Fruit getFruit() {

        return new Apple(); // 返回Fruit类型

    }

}

Apple apple = (Apple) new OldApple().getFruit(); // 需要强制转型

// 原因:早期Java要求返回类型必须完全一致

构造器重载:特殊的重载案例

构造器重载的特点

构造器重载是方法重载的特殊形式,用于以不同方式创建对象:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

class MartialArtsSchool {

    private String name;

    private int studentCount;

    // 默认构造器

    public MartialArtsSchool() {

        this("无名武馆", 10);

    }

    // 重载构造器1

    public MartialArtsSchool(String name) {

        this(name, 20);

    }

    // 重载构造器2

    public MartialArtsSchool(String name, int studentCount) {

        this.name = name;

        this.studentCount = studentCount;

    }

}

反例:构造器重载的常见错误

1

2

3

4

5

6

7

8

9

10

11

class ErrorSchool {

    private String name;

    public ErrorSchool() {

        // 忘记初始化name

    }

    public ErrorSchool(String name) {

        this(); // 调用无参构造器

        this.name = name; // 但无参构造器没初始化

    }

}

// 原因:构造器链调用时要确保所有路径都正确初始化

重写中的super关键字

调用父类实现

重写时经常需要调用父类的原始实现:

1

2

3

4

5

6

7

class ImprovedMaster extends OldMaster {

    @Override

    public void secretMove() {

        super.secretMove(); // 先调用父类方法

        System.out.println("追加新招式:九阳神功");

    }

}

反例:错误使用super

1

2

3

4

5

6

7

8

class WrongMaster extends OldMaster {

    @Override

    public void secretMove() {

        System.out.println("我的新招式");

        super.secretMove(); // 顺序可能不对

    }

}

// 可能的问题:业务逻辑要求先执行父类方法

实战案例:完整的武术系统

综合运用重载和重写

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

// 基础武术类

class MartialArt {

    protected String name;

    public MartialArt(String name) {

        this.name = name;

    }

    // 可重写的方法

    public void practice() {

        System.out.println("练习" + name);

    }

    public void practice(int hours) {

        System.out.println("练习" + name + hours + "小时");

    }

}

// 具体武术类型

class TaiChi extends MartialArt {

    public TaiChi() {

        super("太极拳");

    }

    @Override

    public void practice() {

        System.out.println("以柔克刚:" + name);

    }

    // 重载:新增练习方式

    public void practice(String style) {

        System.out.println("练习" + style + "式" + name);

    }

}

class ShaolinKungfu extends MartialArt {

    public ShaolinKungfu() {

        super("少林功夫");

    }

    @Override

    public void practice() {

        super.practice(); // 调用父类方法

        System.out.println("追加:金钟罩铁布衫");

    }

}

使用示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

public class MartialArtsTest {

    public static void main(String[] args) {

        MartialArt[] arts = {

            new TaiChi(),

            new ShaolinKungfu()

        };

        for (MartialArt art : arts) {

            art.practice(); // 多态:调用实际类型的重写方法

        }

        TaiChi taiChi = new TaiChi();

        taiChi.practice(2);    // 重载:练习太极拳2小时

        taiChi.practice("陈式"); // 重载:练习陈式太极拳

    }

}

常见陷阱和最佳实践

陷阱1:混淆重载和重写

1

2

3

4

5

6

7

8

9

10

11

class ConfusionExample {

    public void method(Object obj) {

        System.out.println("Object版本");

    }

    public void method(String str) {

        System.out.println("String版本");

    }

}

ConfusionExample example = new ConfusionExample();

example.method(null); // 输出:String版本

// 原因:重载解析选择最具体的类型

陷阱2:静态方法的重写误解

1

2

3

4

5

6

7

8

9

10

11

12

13

class Parent {

    public static void staticMethod() {

        System.out.println("父类静态方法");

    }

}

class Child extends Parent {

    public static void staticMethod() {

        System.out.println("子类静态方法");

    }

}

Parent obj = new Child();

obj.staticMethod(); // 输出:父类静态方法(不是多态!)

// 原因:静态方法不支持重写,只支持隐藏

最佳实践总结

记忆口诀

重载重写要分清,同名方法各不同
重载同 class 参数异,编译时分显神通
重写父子 signature 同,运行时分多态功
@Override 是护身符,拼写错误无处藏
静态 final 不能改,private 方法不继承
掌握这两招绝技,Java 江湖任你闯!

记住这些诀窍,你就能在Java的江湖中游刃有余地使用重载和重写了!下次再见,道友们!

原文链接:
相关文章
最新更新