Java Annotations
Metadata for Java code elements
🏷️ What are Annotations?
Annotations provide metadata about program elements like classes, methods, and variables. They don't directly affect program execution but provide information to compilers and tools.
// Basic annotation usage
@Override
public String toString() {
return "Custom string representation";
}
Purpose:
@Override ensures method properly overrides parent method
Compiler checks for correct method signature
Common Annotations
@Override
Indicates method overriding
@Override
public String toString() { }
@Deprecated
Marks outdated elements
@Deprecated
public void oldMethod() { }
@SuppressWarnings
Suppresses compiler warnings
@SuppressWarnings("unchecked")
List list = new ArrayList();
@FunctionalInterface
Marks functional interfaces
@FunctionalInterface
interface Calculator { }
🔹 Built-in Annotations Example
Using common Java annotations in practice:
class Animal {
@Deprecated
public void makeSound() {
System.out.println("Some sound");
}
public void makeNoise() {
System.out.println("Animal noise");
}
}
class Dog extends Animal {
@Override
public void makeNoise() {
System.out.println("Woof!");
}
@SuppressWarnings("deprecation")
public void testDeprecated() {
makeSound(); // Using deprecated method
}
}
// Usage
Dog dog = new Dog();
dog.makeNoise(); // Calls overridden method
Output:
Woof!
@Override ensures correct method signature
@Deprecated warns about old method usage
🔹 Custom Annotations
Creating your own annotations for specific needs:
import java.lang.annotation.*;
// Custom annotation definition
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TestMethod {
String description() default "";
int priority() default 1;
}
// Using custom annotation
public class TestClass {
@TestMethod(description = "Tests addition", priority = 1)
public void testAdd() {
System.out.println("Testing addition");
}
@TestMethod(description = "Tests subtraction", priority = 2)
public void testSubtract() {
System.out.println("Testing subtraction");
}
}
// Reading annotations at runtime
public class AnnotationProcessor {
public static void processAnnotations(Class<?> clazz) {
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(TestMethod.class)) {
TestMethod annotation = method.getAnnotation(TestMethod.class);
System.out.println("Method: " + method.getName());
System.out.println("Description: " + annotation.description());
System.out.println("Priority: " + annotation.priority());
}
}
}
}
Output:
Method: testAdd
Description: Tests addition
Priority: 1
🔹 Meta-Annotations
Annotations that annotate other annotations:
// Meta-annotations for custom annotation
@Retention(RetentionPolicy.RUNTIME) // Available at runtime
@Target({ElementType.TYPE, ElementType.METHOD}) // Can be used on classes and methods
@Documented // Include in JavaDoc
@Inherited // Inherited by subclasses
public @interface MyAnnotation {
String value();
int count() default 1;
}
// Using the annotation
@MyAnnotation(value = "Class level", count = 5)
public class AnnotatedClass {
@MyAnnotation("Method level")
public void annotatedMethod() {
System.out.println("This method is annotated");
}
}
// Checking retention policy
public class RetentionExample {
public static void main(String[] args) {
Class<AnnotatedClass> clazz = AnnotatedClass.class;
if (clazz.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
System.out.println("Value: " + annotation.value());
System.out.println("Count: " + annotation.count());
}
}
}
Output:
Value: Class level
Count: 5