skip to content

What does the @Override annotation do, and why should you use it even though it's optional?

level: juniorimportance: must knowfreq 78%

answer

  1. Compile-time check only, no runtime effect
  2. Catches signature mismatch -> compile error instead of silent overload
  3. Works on interface impls since Java 6
  4. RetentionPolicy.SOURCE, in java.lang
  5. Refactor safety: breaks compile when parent signature changes

basics

~20 s

@Override tells the compiler a method is meant to replace one from a parent class or interface. If it doesn't actually match a parent method, you get a compile error. It catches typos and wrong signatures early.

solid answer

~40 s

@Override is a marker annotation placed on a method to declare that it overrides a method from a superclass or implements one from an interface. It is purely a compile-time check: the compiler verifies that a matching method really exists in a supertype, and if not (a misspelled name, wrong parameter types, wrong return type), compilation fails. Without it, such a mistake silently creates a brand-new method that never gets called, which is a classic hard-to-find bug. It also documents intent for readers and lets IDEs/tools flag broken overrides when a parent signature changes. It has no runtime effect. Since Java 6 it can also annotate methods that implement interface methods, not just class overrides. Best practice is to put @Override on every method that overrides or implements.

code

java · 10 lines
java
class Animal {
    void speak() { System.out.println("..."); }
}

class Dog extends Animal {
    @Override
    void speak() { System.out.println("Woof"); } // verified at compile time

    // @Override void speik() {}  // would NOT compile: typo, no such supertype method
}

go deeper

for a junior

Knows @Override marks an overriding method and that it catches typos; can apply it correctly.

for a middle

Explains the silent overload bug it prevents and that it works for interface methods since Java 6; knows it is source-retention with no runtime effect.

for a senior

Articulates refactoring safety, the override-vs-overload-vs-hide distinction, and why it should be a universal habit; can reason about retention policies.

for a principal

Frames it as part of a defensive coding standard and lint/CI policy (e.g., enforcing @Override via Error Prone/Checkstyle) across a large codebase.

## What an annotation is An **annotation** in Java is metadata you attach to code (a class, method, field, parameter, etc.) using the `@Name` syntax. By itself an annotation does nothing; it is read by the **compiler**, by **tools**, or at **runtime** via reflection. `@Override` is one of the simplest: a **marker annotation** (it has no elements/values) that lives in the `java.lang` package, so it's always available with no import. ## What 'overriding' means In object-oriented programming, a subclass can provide its own version of a method that already exists in its parent class. This is **overriding**. For overriding to actually happen, the new method must have a **matching signature**: same name, same (or compatible) parameter list, and a compatible return type. At runtime, when you call that method on an object, Java picks the most specific (subclass) version. This is **dynamic dispatch**. The same idea applies to **interfaces**: a class that `implements` an interface provides the bodies for the interface's abstract methods. ## The problem @Override solves Suppose the parent has `public boolean equals(Object o)` and you write `public boolean equals(MyType o)` in the subclass. The parameter type differs, so you have **not** overridden `equals` — you've created an unrelated **overload** that callers using `Object` will never invoke. Your code compiles and runs, but the wrong method executes. These bugs are very hard to spot. `@Override` makes the compiler verify that a matching supertype method truly exists. If it doesn't, you get a **compile-time error** immediately, turning a silent runtime bug into an obvious one at build time. ```java class Parent { public boolean equals(Object o) { return false; } } class Child extends Parent { @Override public boolean equals(MyType o) { return true; } // COMPILE ERROR: does not override } ``` ## When the check applies - Overriding a superclass method. - Since **Java 6**, implementing an interface method also accepts `@Override` (before Java 6 this was a compile error). - It does **not** apply to a brand-new method, a static method 'hiding' a parent static method counts as hiding not overriding, and it cannot go on constructors. ## Other benefits - **Documentation:** readers instantly see the method is tied to a supertype contract. - **Refactoring safety:** if someone changes or removes the parent method's signature, every `@Override` that no longer matches fails to compile, so you find all the places to update. - **Zero runtime cost:** `@Override` has `RetentionPolicy.SOURCE` — it is discarded after compilation and never appears in the `.class` file. ## Takeaway Always add `@Override` to overriding/implementing methods. It costs nothing, documents intent, and converts a whole class of silent bugs into compile errors.

  • What happens if you put @Override on a method that doesn't match any supertype method?
    You get a compile-time error stating the method does not override or implement a method from a supertype.
  • Does @Override exist in the compiled .class file?
    No. It has RetentionPolicy.SOURCE, so it is discarded after compilation and is not present at runtime.

saying these in an interview costs you the question

  • Thinking @Override changes runtime behavior or 'forces' an override
  • Believing it is required for overriding to work
  • Claiming it can be placed on constructors or new methods
  • Not knowing it works on interface implementations since Java 6

context