杰瑞科技汇

Java注解如何实现自定义功能?

Of course! Let's dive deep into Java Annotations, from the basics to advanced concepts.

Java注解如何实现自定义功能?-图1
(图片来源网络,侵删)

What is a Java Annotation?

In simple terms, a Java annotation is a form of metadata (data about data) that you can add to your Java code. It doesn't directly affect the program's logic but provides information to the compiler, the runtime, or other tools.

Think of it like a sticky note you attach to your code to give instructions or descriptions to other tools (like the compiler, a testing framework, or a web server).

Key Characteristics:

  • Metadata: It provides data about the program, not the program logic itself.
  • Doesn't Change Code Behavior: Annotations don't execute code directly. Their effect is realized when they are processed by a tool.
  • Syntactic Sugar: They are declared using the symbol, making them easy to spot in the code.

Why Use Annotations? (The "Why")

Annotations make code cleaner, more declarative, and easier to maintain. Instead of writing complex, often repetitive, boilerplate code, you can use a simple annotation to achieve the same result.

Example Without Annotation (The Old Way): Imagine you want to create a web endpoint. You might have to write a lot of framework-specific code to register the URL, map parameters, etc.

Java注解如何实现自定义功能?-图2
(图片来源网络,侵删)

Example With Annotation (The Modern Way): With a framework like Spring, you can do this:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
    @GetMapping("/greeting")
    public String greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
        return "Hello, " + name + "!";
    }
}

The @RestController, @GetMapping, and @RequestParam annotations are all metadata that tells the Spring framework how to configure this component and its behavior.


Built-in Java Annotations

Java comes with several built-in annotations for core language features.

Annotations for the Compiler

These annotations are used to give hints to the Java compiler.

Java注解如何实现自定义功能?-图3
(图片来源网络,侵删)
  • @Override

    • Purpose: Tells the compiler that a method is intended to override a method from a superclass.
    • Benefit: If you misspell the method name or use the wrong parameters, the compiler will throw an error instead of silently creating a new method. This prevents subtle bugs.
    • Example:
      @Override
      public String toString() {
          return "MyObject";
      }
  • @Deprecated

    • Purpose: Marks a class, method, or field as outdated. It warns other developers that this element should no longer be used.
    • Benefit: Provides a clear signal to API users to migrate to a newer alternative.
    • Example:
      @Deprecated
      public void oldMethod() {
          // ... old logic ...
      }
  • @SuppressWarnings

    • Purpose: Suppresses compiler warnings. It's used when you are aware of a potential issue and have consciously decided it's not a problem.
    • Benefit: Cleans up your code by hiding warnings you can't or don't want to fix.
    • Example:
      @SuppressWarnings("unchecked") // Suppresses warning about raw types
      public List<String> createList() {
          return (List<String>) new ArrayList(); // This would normally warn
      }

Annotation for Inheritance

  • @Retention(RetentionPolicy.SOURCE)
    • Purpose: This is a meta-annotation (an annotation on another annotation). It's used with @SuppressWarnings to indicate that the annotation is only needed by the compiler and should be discarded after compilation.
    • Example: The @SuppressWarnings annotation itself is annotated with @Retention(RetentionPolicy.SOURCE).

Custom Annotations (Creating Your Own)

You can create your own annotations to define your own metadata. This is where the real power lies.

Step 1: Define the Annotation

Use the @interface keyword to define a new annotation type.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
// @Target specifies where this annotation can be used.
// Here, it can only be applied to methods.
@Target(ElementType.METHOD)
// @Retention specifies how long the annotation should be retained.
// RUNTIME means it will be available at runtime, allowing reflection.
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    // You can define elements (like methods) in an annotation.
    // They act like key-value pairs.
    String value(); // A required element named 'value'
    int priority() default 1; // An optional element with a default value
}

Step 2: Apply the Annotation

Use your custom annotation on your code.

public class MyService {
    @MyAnnotation(value = "Important operation", priority = 10)
    public void performTask() {
        System.out.println("Performing an important task...");
    }
    @MyAnnotation(value = "Regular operation")
    public void doSomethingElse() {
        System.out.println("Doing something else...");
    }
}

Step 3: Process the Annotation (Using Reflection)

To make the annotation do something, you need a processor. The most common way is using reflection at runtime.

import java.lang.reflect.Method;
public class AnnotationProcessor {
    public static void main(String[] args) {
        // Get the class object
        Class<MyService> serviceClass = MyService.class;
        // Get all declared methods
        Method[] methods = serviceClass.getDeclaredMethods();
        for (Method method : methods) {
            // Check if the method has our annotation
            if (method.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
                // Access the elements of the annotation
                String description = annotation.value();
                int priority = annotation.priority();
                System.out.println("Method: " + method.getName());
                System.out.println("  Description: " + description);
                System.out.println("  Priority: " + priority);
                System.out.println("----------------------------");
            }
        }
    }
}

Output:

Method: performTask
  Description: Important operation
  Priority: 10
----------------------------
Method: doSomethingElse
  Description: Regular operation
  Priority: 1
----------------------------

Meta-Annotations (Annotations on Annotations)

These are annotations that annotate other annotations. They are crucial for defining how your custom annotations behave.

  • @Target: Specifies the Java elements that an annotation can be applied to.

    • ElementType.TYPE (class, interface, enum)
    • ElementType.METHOD (method)
    • ElementType.FIELD (field/variable)
    • ElementType.PARAMETER (method parameter)
    • ... and others.
  • @Retention: Specifies how long the annotation should be kept.

    • RetentionPolicy.SOURCE: Discarded by the compiler. (e.g., @SuppressWarnings)
    • RetentionPolicy.CLASS: Available to the compiler but not to the JVM at runtime. (This is the default).
    • RetentionPolicy.RUNTIME: Available to the JVM at runtime. This is required for reflection-based processing.
  • @Documented: Indicates that this annotation should be documented by Javadoc tools.

  • @Inherited: If an annotation with @Inherited is applied to a class, then the annotation is automatically inherited by its subclasses.


Common Use Cases in Popular Frameworks

Annotations are the backbone of modern Java frameworks.

Framework Annotation Purpose
Spring @Component, @Service, @Repository Marks a class as a Spring bean, making it a candidate for auto-detection and registration.
@Autowired Injects dependencies (other beans) automatically.
@Value Injects values from a properties file.
@RestController, @GetMapping, @PostMapping Defines RESTful web services and HTTP mappings.
JUnit 5 @Test Marks a method as a test case.
@BeforeEach, @AfterEach Marks a method to run before/after each test.
@BeforeAll, @AfterAll Marks a method to run once before/after all tests in a class.
Hibernate/JPA @Entity Marks a class as a persistent entity (a table in the database).
@Id Specifies the primary key of an entity.
@GeneratedValue Specifies the generation strategy for the primary key.
@Column Maps a field to a specific column in the database table.

Summary: Annotation Processing Lifecycle

  1. Source Code: You write annotations in your source code.
  2. Compile Time: The compiler can process annotations (e.g., @Override, @SuppressWarnings).
  3. Class File: Annotations are stored in the .class file if RetentionPolicy.CLASS or RUNTIME is used.
  4. Runtime: If RetentionPolicy.RUNTIME is used, you can use reflection to read the annotation data and perform actions (e.g., Spring dependency injection, JUnit test execution).

Annotations are a powerful and essential feature of modern Java, enabling clean, declarative, and highly configurable code.

分享:
扫描分享到社交APP
上一篇
下一篇