跳转至

附录:Java 中的重写、重载与注解

☕ 课前导语:为什么需要补给?

在马上要开始的 Web 开发实战中,你可能会经常遇到一些似曾相识却又说不清楚的语法: 为什么有的方法名字一样却不报错?为什么子类里的方法头上要顶着一个 @Override?我们在写网页后台时,挂在类头顶上的 @WebServlet 到底是个啥魔法?

别慌!这篇附录专为刚入门 Java 的你准备。我们将用最通俗的语言,带你迅速攻克 Java 开发必用的三大核心概念:重载 (Overload)重写 (Override)注解 (Annotation)


🎭 一、重载 (Overloading):同名不同躯的“多面手”

1. 什么是重载?

重载 (Overload) 发生在一个类里面。指的是你可以写多个名字完全相同的方法,只要它们的参数列表不同(参数的个数、类型或者顺序不同)即可。

💡 生活比喻: 就像一个名叫“做饭 (cook)”的厨师:
- 你给他面条,他就给你做一碗牛肉面 cook(Noodle n)
- 你给他米饭和鸡蛋,他就给你做蛋炒饭 cook(Rice r, Egg e)
厨师的名字都叫 cook,但他会根据你给的材料(参数)不同,做出不同的反应。

2. 代码演示

public class Calculator {

    // 方法 1:两个整数相加
    public int add(int a, int b) {
        return a + b;
    }

    // 方法 2:三个整数相加(参数个数不同,构成重载!)
    public int add(int a, int b, int c) {
        return a + b + c;
    }

    // 方法 3:两个小数相加(参数类型不同,构成重载!)
    public double add(double a, double b) {
        return a + b;
    }
}

避坑指南

重载只看方法名和参数列表,和方法的“返回值类型”没有任何关系! 如果你写了 public int add(int a)public double add(int a),编译器会直接报错。


🧬 二、重写 (Overriding):青出于蓝的“子类逆袭”

1. 什么是重写?

重写 (Override) 发生在父类与子类(或接口与实现类)之间。当子类对父类中已经存在的方法不满意时,可以照抄父类的方法签名(名字、参数完全一样),但是重新编写里面的代码逻辑

💡 生活比喻: 你的老爸(父类)传给你了一家面馆,里面有一道祖传菜叫 makeSoup()(熬汤),老配方是用猪骨熬。 你接手后觉得太油腻了,于是你保留了 makeSoup() 这个招牌(方法名不变),但是在后厨把做法改成了用牛骨熬(重写了方法体)。

2. 代码演示:面馆的传承与创新

// 父类:老爸的传统面馆
public class NoodleShop {
    // 祖传熬汤方法
    public void makeSoup() {
        System.out.println("传统老店:使用猪骨熬制浓汤 8 小时...");
    }
}

// 子类:你接手后的新面馆 (继承了老爸的面馆)
public class MyNoodleShop extends NoodleShop {

    // 重写了父类的 makeSoup 方法,招牌没变,但做法变了
    @Override 
    public void makeSoup() {
        System.out.println("创新面馆:使用清汤牛骨和几十味香料熬制!"); 
    }
}

3. 进阶实战:重写带来的“多态”魔法

理解了重写,我们来看一个在框架底层极为常见的“神仙操作”。假设我们有这样一个场景:

// 父类:普通人
public class Person {
    private String name;

    public Person(String name) { this.name = name; }
    public String getName() { return name; }

    // 核心行为:吃饭
    public void eat(){
        System.out.println(name + " 正在随便吃点东西");
    }

    // 一个通用的调用方法,内部调用了 eat()
    public void callEat(){
        System.out.println("--- 准备开饭 ---");
        eat(); // 注意这里!
    }
}

// 子类:教师
public class Teacher extends Person {

    public Teacher(String name) {
        super(name);
    }

    // 教师重写了吃饭方法
    @Override
    public void eat() {
        System.out.println(getName() + " 老师正在教工食堂愉快地用餐");
    }
}

现在,我们在 main 方法中运行以下代码,你猜猜会输出什么?

1
2
3
4
public static void main(String[] args) {
    Teacher teacher = new Teacher("陈");
    teacher.callEat(); 
}

运行结果:

--- 准备开饭 ---
陈 老师正在教工食堂愉快地用餐

🕵️‍♂️ 揭秘时刻(动态绑定): 当你调用 teacher.callEat() 时,因为 Teacher 类里没有写这个方法,程序会去父类 Person 里找,并且开始执行 Person 里的 callEat()。 最神奇的地方在于:当父类的 callEat() 执行到内部的 eat() 时,Java 虚拟机(JVM)非常聪明,它在运行期间发现,“虽然我现在在父类的代码里,但实际让我干活的是一个 Teacher 对象!” 于是,它果断地动态绑定到了子类 Teacher 重写后的 eat() 方法上。

这就是面向对象三大特性之一——多态的魅力!掌握了这个机制,以后看框架底层代码(比如模板方法模式)就会豁然开朗。


⚔️ 三、核心对比:重载 vs 重写 (面试高频题!)

为了方便记忆,请把下面这个表格印在脑子里:

维度 重载 (Overload) 重写 (Override)
发生位置 同一个类 子类与父类之间
方法名 必须相同 必须相同
参数列表 必须不同 (个数/类型/顺序) 必须相同
返回值类型 无所谓 必须相同 (或是其子类)
通俗理解 一个方法的多种表现形式 (多面手) 子类改造父类的方法 (青出于蓝)

🏷️ 四、注解 (Annotation):代码里的“神奇便利贴”

在马上要开始的 Web 开发实战中,你会经常看到类似 @WebServlet@Data 这样的东西挂在代码头上。它们到底是什么?

1. 什么是注解?

注解 (Annotation) 就是贴在代码(类、方法、变量)上的一张“便利贴”“配置标签”

注意一个极其核心的概念: 注解本身是不干活的!它只负责携带信息。 真正干活的是读取这些标签的“幕后黑手”(比如 Java 编译器,或者 Tomcat 服务器运行时用到的一种叫做“反射”的技术)。

💡 生活比喻
你在超市买水果,苹果上贴了一个标签 @打折
这个标签自己能让价格变低吗?不能。
但是,当收银员(Tomcat 服务器)看到这个 @打折 标签时,他就会在系统里给你按 8 折结账。

2. 括号里的参数:给便利贴加点“详细备注”

有时候,光贴一个 @打折 标签还不够,收银员会问:“到底打几折?” 这时候,我们就需要在括号里加上具体的参数(属性值)。

注解括号里的内容,本质上就是传递给“幕后黑手”的具体指令参数

  • 带参数的便利贴@打折(discount = 0.8) 告诉系统,具体按 8 折计算。
  • 带多个参数的便利贴:在 Servlet 开发中,你可能会看到: @WebServlet(name = "LoginServlet", urlPatterns = "/login", loadOnStartup = 1) 这就像贴了一张信息量满满的标签,告诉 Tomcat:“这个类的代号叫 LoginServlet,它负责处理 /login 的网址请求,并且在服务器一启动时就把这个类加载进内存。”

😎 一个常见的“偷懒”语法(单值省略): 如果在定义注解时,里面有一个属性的名字刚好叫 value,并且你只打算给这一个属性赋值,那么 Java 允许你把 value = 这几个字母省略掉!

所以,你在代码里最常看到的: @WebServlet("/login") 其实就是 @WebServlet(value = "/login") 的简写!这种设计纯粹是为了让程序员少敲几下键盘,让代码看起来更清爽。

3. 常见的三大类注解

① 编译器的检查贴纸 (JDK 自带)

最典型的就是我们在前面见过的 @Override。 注意,这个注解后面没有括号,因为它不需要额外的参数。你把它贴在方法上,仅仅是给 Java 编译器发个信号:“嘿!老哥,我这个方法是重写父类的,你帮我检查一下有没有拼错。”

② 简化代码的魔法贴纸 (比如 Lombok 插件)

在后续操作数据库时,我们需要写大量的实体类(比如 UserOrder)。只要贴上一个 @Data,Lombok 插件看到这个便利贴,就会默默地在底层帮你生成所有的 get/set、无参构造等方法。

③ Web 服务器的“指路牌” (Servlet 核心注解)

这是我们在课程中打交道最多的注解!

🕰️ 时代的眼泪:在以前的旧项目中,为了告诉 Tomcat 服务器“哪个网址对应哪段代码”,程序员需要在一个叫 web.xml 的文件里写上七八行臃肿的 XML 配置。每次加个网页都要去改,极度痛苦。

现在,我们只需要贴便利贴:

  • 贴了 @WebServlet("/login"),Tomcat 启动时一扫描,就会明白:“哦!当用户在浏览器访问 /login 路径时,就把请求交给这个类处理。”
  • 贴了 @WebFilter("/*"),Tomcat 就知道这是一个全局过滤器,所有请求(/* 代表所有路径)进来之前都要先经过它这道关卡检查。

4. 如何看待满屏的注解?

初学者看到框架里密密麻麻的注解和括号里的各种参数,容易感到心虚,其实大可不必。每次看到一个新注解,你只需要在心里问自己三个问题:

  1. 这个标签是贴给谁看的?(给编译器?给 Tomcat?还是给未来的 Spring 框架?)
  2. 那个“幕后黑手”看到它之后,会帮我自动做一件什么事情?
  3. 括号里的参数,是为了给它提供什么补充信息?

理清了这个逻辑,你就能从繁琐的配置中解脱出来,真正体会到框架带来的开发效率飞跃!🚀