JavaAnnotations

Annotations

An annotation is metadata you attach to code — a class, method, field, or parameter — using @Name syntax. Crucially, an annotation by itself doesn't change what your program does; it doesn't contain executable logic. What it does is provide information about your code to the compiler, to development tools, or to other code that inspects it at runtime (typically via reflection).

Common built-in annotations

Annotation

Purpose

@Override

Tells the compiler this method is meant to override a superclass method — if it doesn't actually match a superclass signature, compilation fails instead of silently creating a new method.

@Deprecated

Marks a method, class, or field as discouraged for new use; the compiler emits a warning wherever it is referenced.

@SuppressWarnings

Tells the compiler to suppress specific warning categories (e.g. @SuppressWarnings("unchecked")) for the annotated element, useful for known-safe generic operations after type erasure.

@FunctionalInterface

Documents that an interface is intended to have exactly one abstract method (so it can be used as a lambda target) — the compiler enforces that constraint if you accidentally add a second abstract method.

Built-in annotations in practice

Java
public class Animal {
    public String makeSound() {
        return "...";
    }

    @Deprecated
    public String oldMakeSound() {
        return makeSound();
    }
}

public class Dog extends Animal {
    @Override
    public String makeSound() {   // compiler checks this really overrides Animal.makeSound
        return "Woof!";
    }
}

@FunctionalInterface
interface Greeter {
    String greet(String name); // exactly one abstract method
}
Writing a custom annotation

You can define your own annotations with the @interface keyword. Two meta-annotations control how a custom annotation behaves: @Target restricts what kinds of declarations it can be placed on (methods, fields, types, and so on), and @Retention controls how long the annotation information is kept — discarded after compilation, kept in the compiled .class file, or kept available at runtime so reflection can read it.

A simple custom annotation

Java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)  // keep it available for reflection at runtime
@Target(ElementType.METHOD)          // only methods can be annotated with this
public @interface Test {
}

public class Calculator {
    @Test
    public void additionWorks() {
        // a testing framework could scan for @Test methods and run them
    }
}
Annotations plus reflection power whole frameworks
Custom annotations rarely do anything on their own — they become powerful when combined with reflection, which can scan a program at runtime looking for particular annotations and act on what it finds. This combination is the foundation many frameworks are built on: Spring uses annotations like `@Autowired` and `@Service` to wire up dependency injection, and JUnit uses `@Test` to discover which methods to run. The Reflection page covers how that runtime inspection actually works.
  • Annotations attach metadata to code without changing its runtime behavior on their own.

  • @Override, @Deprecated, @SuppressWarnings, and @FunctionalInterface are common built-in annotations checked by the compiler.

  • Custom annotations use @interface; @Retention controls how long they persist, @Target restricts where they can be used.

  • Frameworks like Spring and JUnit combine custom annotations with reflection to power dependency injection and test discovery.