ZetCode

Java @Override 注解

最后修改时间:2025 年 4 月 13 日

@Override 注解是 Java 中的一个标记注解,它显式地表示一个方法旨在覆盖(Override)父类或接口中的方法。通过使用 @Override,开发人员可以确保覆盖的方法被正确定义,防止可能未被注意到的意外不匹配或拼写错误。

@Override 的主要优点之一是它能够在编译时检测错误。如果被注解的方法没有成功覆盖父类或接口中的方法(由于不正确的方法签名或缺少父类定义),编译器将生成一个错误。这种保护措施有助于强制执行正确的继承实践并减少调试工作。

除了防止错误之外,@Override 通过明确哪些方法旨在覆盖父类实现来提高代码的可读性。这改进了代码维护,使开发人员更容易在大型或协作项目中进行修改。

通过始终如一地应用 @Override 注解,开发人员可以编写更健壮、更易于维护且抗错误的 Java 代码,同时遵守面向对象的原则。

@Override 的基本用法

@Override 最简单的用法是覆盖父类中的方法。该注解直接放在方法声明之前。这确保您实际上是在按预期覆盖方法。

Main.java
package com.zetcode;

class Animal {
    public void makeSound() {
        System.out.println("Animal makes a sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog barks");
    }
}

public class Main {

    public static void main(String[] args) {
        Animal myDog = new Dog();
        myDog.makeSound(); // Outputs: Dog barks
    }
}

在此示例中,Dog 类覆盖了 Animal 类中的 makeSound 方法。@Override 注解确认这是一个有意的覆盖。如果我们拼错了方法名称,编译器会捕获它。

使用 @Override 实现接口

@Override 也可以在实现接口方法时使用。这有助于确保您正确地实现了所有必需的接口方法。编译器将验证方法签名是否匹配。

Main.java
package com.zetcode;

interface Shape {
    double calculateArea();
    String getName();
}

class Circle implements Shape {
    private double radius;
    
    public Circle(double radius) {
        this.radius = radius;
    }
    
    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }
    
    @Override
    public String getName() {
        return "Circle";
    }
}

public class Main {

    public static void main(String[] args) {
        Shape circle = new Circle(5.0);
        System.out.println(circle.getName() + " area: " + 
                         circle.calculateArea());
    }
}

在这里,Circle 实现了 Shape 接口。两个接口方法都用 @Override 标记。如果我们更改了方法签名,编译器会将其标记为与接口不匹配。

使用 @Override 检测错误

@Override 的一个关键好处是尽早发现错误。如果您认为您正在覆盖一个方法但实际上没有,编译器会警告您。这可以防止细微的错误潜入您的代码。

Main.java
package com.zetcode;

class Vehicle {
    public void startEngine() {
        System.out.println("Engine started");
    }
}

class Car extends Vehicle {
    @Override
    public void startEngin() { // Misspelled method name
        System.out.println("Car engine started");
    }
}

public class Main {

    public static void main(String[] args) {
        Vehicle myCar = new Car();
        myCar.startEngine(); // Calls Vehicle's method
    }
}

在这个例子中,我们打算覆盖 startEngine 但拼写错误为 startEngin@Override 注解导致编译器将其标记为错误。如果没有它,代码会编译但行为会出乎意料。

覆盖 Object 类方法

Object 类提供了所有 Java 对象继承的基本方法。常用的覆盖方法(例如 toStringequalshashCode)应始终使用 @Override 注解。这确保了覆盖的方法保持正确的签名和行为,防止因意外的错误定义而导致的错误。

Main.java
package com.zetcode;

import java.util.Objects;

class Person {

    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

public class Main {

    public static void main(String[] args) {
        Person p1 = new Person("Alice", 30);
        Person p2 = new Person("Alice", 30);
        
        System.out.println(p1);
        System.out.println("p1 equals p2: " + p1.equals(p2));
    }
}

此示例正确地覆盖了三个重要的 Object 方法。

使用 Objects.equals(name, person.name) 而不是 name.equals(person.name) 可以防止潜在的 NullPointerException 问题。 类似地,Objects.hash(name, age) 简化了哈希码生成,同时确保了良好分布的哈希。

通过遵循这些最佳实践,开发人员可以创建可靠、高效且可维护的 Java 类,这些类可以与核心 Java 框架和数据结构无缝协作。

抽象类方法覆盖

扩展抽象类时,@Override 应被用于抽象方法的所有具体实现。 这可以阐明代码的意图,并有助于捕获签名不匹配。

Main.java
package com.zetcode;

abstract class Shape {
    public abstract double calculateArea();
    public abstract void draw();
    public void describe() {
        System.out.println("This is a shape");
    }
}

class Circle extends Shape {
    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    @Override
    public double calculateArea() {
        return Math.PI * radius * radius;
    }

    @Override
    public void draw() {
        System.out.println("Drawing a circle with radius " + radius);
    }

    @Override
    public void describe() {
        System.out.println("This is a circle with radius " + radius);
    }
}

public class Main {

    public static void main(String[] args) {
        Shape circle = new Circle(5.0);
        circle.draw();
        System.out.println("Area: " + circle.calculateArea());
        circle.describe();
    }
}

在这里,Circle 实现了两个抽象方法并覆盖了 Shape 中的一个具体方法。 所有覆盖都用 @Override 标记。 编译器确保每个方法都正确匹配其父声明。

覆盖泛型类中的方法

使用泛型类时,@Override 有助于确保方法覆盖中的类型安全。 该注解验证方法签名,包括泛型类型参数。

Main.java
package com.zetcode;

class Box<T> {
    private T content;
    
    public void setContent(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
}

class StringBox extends Box<String> {
    @Override
    public void setContent(String content) {
        if (content == null || content.isEmpty()) {
            throw new IllegalArgumentException("Content cannot be empty");
        }
        super.setContent(content);
    }
    
    @Override
    public String getContent() {
        String content = super.getContent();
        return content != null ? content.toUpperCase() : null;
    }
}

public class Main {

    public static void main(String[] args) {
        StringBox box = new StringBox();
        box.setContent("hello");
        System.out.println(box.getContent()); // Outputs: HELLO
    }
}

在此示例中,StringBox 扩展了 Box<String> 并覆盖了其方法。 @Override 注解确认我们正在使用特定的 String 实现正确覆盖泛型方法。 编译器检查类型兼容性。

默认接口方法和 @Override

Java 8 引入了接口中的默认方法。 覆盖这些默认方法时,应使用 @Override 以明确意图并捕获潜在错误。

Main.java
package com.zetcode;

interface Logger {
    default void log(String message) {
        System.out.println("Default log: " + message);
    }
    
    void error(String message);
}

class FileLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("File log: " + message);
    }
    
    @Override
    public void error(String message) {
        System.out.println("File error: " + message.toUpperCase());
    }
}

public class Main {

    public static void main(String[] args) {
        Logger logger = new FileLogger();
        logger.log("test message");
        logger.error("something went wrong");
    }
}

此示例显示了一个 FileLogger,它覆盖了 Logger 接口中的默认方法 (log) 和抽象方法 (error)。 @Override 注解清楚地表明了哪些方法正在被覆盖,并确保了正确的签名。

来源

Java @Override 注解文档

本教程涵盖了 @Override 注解的所有关键方面,并提供了实际示例。 正确使用 @Override 可以通过及早发现错误来使您的代码更健壮、更具可读性和可维护性。

作者

我叫 Jan Bodnar,是一位敬业的程序员,在该领域拥有多年的经验。我于 2007 年开始撰写编程文章,此后撰写了超过 1,400 篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程