Java 注解(Annotation) 是Java语言中一种元数据形式,它提供了一种在代码中添加元数据的方式。注解为程序员提供了向代码中添加额外信息的能力,这些额外信息可以被编译器、工具或者运行时环境使用。
优点:
缺点:
元注解也是一种注解,用于对其他注解进行注释。Java提供了几种元注解,用于自定义和修饰注解声明,包括以下几种:
SOURCE
、CLASS
和RUNTIME
;在Java中,我们可以自定义注解,以满足特定的需求。自定义注解使用@interface
关键字进行声明。
下面是一个使用上文元注解的简单演示案例程序,展示了如何在Java中应用这些注解来自定义一个注解:
import java.lang.annotation.*;
// 定义一个自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@Repeatable(MyAnnotations.class)
@interface MyAnnotation {
String value() default "";
}
// 定义一个可重复注解容器
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface MyAnnotations {
MyAnnotation[] value();
}
// 使用自定义注解
@MyAnnotation("Class Annotation")
public class DemoClass {
@MyAnnotation("Field Annotation")
private String field;
@MyAnnotation("Constructor Annotation")
public DemoClass() {
// 构造函数注解
}
@MyAnnotation("Method Annotation")
public void demoMethod() {
// 方法注解
}
public static void main(String[] args) {
DemoClass obj = new DemoClass();
Class<? extends DemoClass> clz = obj.getClass();
// 获取类上的注解
MyAnnotation classAnnotation = clz.getAnnotation(MyAnnotation.class);
System.out.println("Class Annotation: " + classAnnotation.value());
// 获取字段上的注解
try {
java.lang.reflect.Field field = clz.getDeclaredField("field");
MyAnnotation fieldAnnotation = field.getAnnotation(MyAnnotation.class);
System.out.println("Field Annotation: " + fieldAnnotation.value());
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
// 获取构造函数上的注解
try {
java.lang.reflect.Constructor<?> constructor = clz.getDeclaredConstructor();
MyAnnotation constructorAnnotation = constructor.getAnnotation(MyAnnotation.class);
System.out.println("Constructor Annotation: " + constructorAnnotation.value());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
// 获取方法上的注解
try {
java.lang.reflect.Method method = clz.getDeclaredMethod("demoMethod");
MyAnnotation methodAnnotation = method.getAnnotation(MyAnnotation.class);
System.out.println("Method Annotation: " + methodAnnotation.value());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
这段代码演示了如何定义和使用自定义注解,并从类、字段、构造函数和方法中获取注解的值。
首先,我定义了一个自定义注解 @MyAnnotation
。注解的定义可以通过多个元注解修饰,这些元注解用于为注解提供额外的信息:
@Retention(RetentionPolicy.RUNTIME)
:指定注解保留的生命周期为运行时。这意味着注解将在运行时仍然可见,可以通过 Java 反射机制获取;@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD,ElementType.CONSTRUCTOR})
:指定注解可以应用于类、字段、方法和构造函数上;@Documented
:指定该注解将包含在 Javadoc 中;@Inherited
:指定子类默认继承父类的注解。之后,在 DemoClass
类上、类中的字段、构造函数和方法上都使用了自定义注解 @MyAnnotation
。
在 main
方法中,首先创建了一个 DemoClass
对象 obj
,通过反射获取 DemoClass
类的实例对象的运行时类型以及类上的注解。
接着,通过反射机制分别获取字段上的注解、构造函数上的注解、方法上的注解。并且打印了相应注解的值,以演示如何从类、字段、构造函数和方法中获取注解的值。
通过自定义注解,我们可以根据需要添加元数据,并在代码中使用它。
Java提供了很多内置的注解,我们来介绍几个常用的注解:
@Override
:用于标记方法覆写(重写)父类的方法,可以帮助我们检查是否正确地覆写了方法;@Deprecated
:用于标记过时的方法或类,在程序中使用过时的元素会收到警告提示,鼓励使用更合适的替代方案;@SuppressWarnings
:用于抑制编译器产生的警告信息,可以让代码看起来更整洁,但需谨慎使用;@FunctionalInterface
:用于标记函数式接口(只有一个抽象方法),可以确保接口的语义符合函数式编程的要求。下面是一个使用Java实现的演示案例程序,展示了如何使用@Override
、@Deprecated
、@SuppressWarnings
和@FunctionalInterface
注解:
import java.util.ArrayList;
import java.util.List;
class Parent {
public void display() {
System.out.println("Parent class");
}
}
class Child extends Parent {
@Override
public void display() {
System.out.println("Child class");
}
}
@Deprecated
class DeprecatedClass {
@Deprecated
public void deprecatedMethod() {
System.out.println("\nThis method is deprecated.");
}
}
@SuppressWarnings("unused")
class SuppressWarningsClass {
// unused field
private int unusedVariable;
@SuppressWarnings("unchecked")
public void suppressWarningsMethod() {
List list = new ArrayList();
list.add("item");
System.out.println("\n" + list);
}
}
@FunctionalInterface
interface FunctionalInterfaceExample {
void someMethod();
}
public class AnnotationDemo {
public static void main(String[] args) {
// @Override example
Parent parent = new Parent();
Child child = new Child();
parent.display(); // Output: Parent class
child.display(); // Output: Child class
// @Deprecated example
DeprecatedClass deprecatedObject = new DeprecatedClass();
deprecatedObject.deprecatedMethod(); // Output: This method is deprecated.
// @SuppressWarnings example
SuppressWarningsClass suppressWarningsObject = new SuppressWarningsClass();
suppressWarningsObject.suppressWarningsMethod(); // No warning will be generated
// @FunctionalInterface example
FunctionalInterfaceExample functionalInterfaceObject = () -> System.out.println("\nFunctional Interface");
functionalInterfaceObject.someMethod(); // Output: Functional Interface
}
}
在这个示例程序中,我们创建了Parent
类和Child
类,其中Child
类使用@Override
注解来标记覆写(重写)了Parent
类中的display()
方法。这样在编译时,如果有错误地覆写了父类的方法,编译器将会给出错误提示。
另外,我们还创建了一个名为DeprecatedClass
的过时类,并在其中的方法和类声明上都使用了@Deprecated
注解。当我们在程序中使用过时的方法或类时,编译器会发出警告,鼓励我们使用更合适的替代方案。
同样,我们还创建了一个名为SuppressWarningsClass
的类,在该类的方法和字段上使用了@SuppressWarnings
注解来抑制编译器产生的警告信息,以便让代码看起来更整洁。但是需要注意,谨慎使用此注解,确保其使用场景合理。
再者,我们创建了一个函数式接口FunctionalInterfaceExample
,并使用@FunctionalInterface
注解进行标记。这个注解可以确保该接口只有一个抽象方法,从而符合函数式编程的要求。
最后,在main
方法中展示了如何使用这些注解的例子,运行程序验证结果如下:
Parent class
Child class
This method is deprecated.
[item]
Functional Interface
Java注解广泛应用于各个领域,包括但不限于以下几个方面:
在各个流行框架中,注解都起着重要的作用。它们为开发者提供了一种简洁、灵活和快速的方式来配置和扩展应用程序。
下面列举了一些主要流行框架中注解的应用范例:
Spring :
@Component
:标记类为一个可被Spring容器管理的组件;@Controller
:标记控制器类,用于处理用户请求;@RequestMapping
:在控制器方法上定义路由规则与请求的映射关系;@Service
:标记服务层类,在业务逻辑中使用;@Repository
:标记数据访问层类,使得 Spring 可以自动将其纳入到 bean 容器;@Autowired
:自动将依赖注入到相应的类中,简化了组件间的耦合关系;@Configuration
:标记类为Spring配置类;@Bean
:标记方法返回值为Spring Bean,并由容器管理。Spring Boot :
@SpringBootApplication
:标记引导类,表示一个 Spring Boot 应用程序入口点;@RestController
:结合了 @Controller
和 @ResponseBody
,用于构建 RESTful API 控制器;@RequestMapping
:指定请求的 URL 路径和 HTTP 方法与方法的映射关系;@ConfigurationProperties
:绑定属性文件或环境变量到 Java Bean,方便地进行配置管理;@EnableAutoConfiguration
:启用自动配置,根据类路径下的依赖和规则推断、添加 Bean。Spring Cloud :
@EnableDiscoveryClient
:启用服务发现;@EnableCircuitBreaker
:启用断路器;@FeignClient
:声明一个可调用远程服务的客户端接口;@EnableZuulProxy
:启用Zuul代理网关;@LoadBalanced
:启用负载均衡客户端。Spring MVC :
@Controller
:标记类为MVC控制器;@RequestMapping
:将请求映射到控制器的方法上;@RequestParam
:将请求参数映射到方法参数上;@PathVariable
:将URL路径变量映射到方法参数上;@ResponseBody
:将方法返回值序列化成响应主体。MyBatis :
@Mapper
:标记接口为MyBatis的映射器;@Select
:定义查询语句;@Insert
:定义插入语句;@Update
:定义更新语句;@Delete
:定义删除语句;@Param
:指定方法参数与SQL语句中的参数对应关系等。Hibernate :
@Entity
:声明实体类;@Table
:指定实体类与数据库表之间的映射关系;@Column
:定义属性与数据库列之间的映射关系;@Id
:标识实体类的主键属性;@GeneratedValue
:指定主键生成策略;@ManyToOne
:定义多对一关系。Junit :
@Test
:标记测试方法;@Before
:在每个测试方法执行前被执行的方法;@After
:在每个测试方法执行后被执行的方法;@RunWith
:指定测试运行器,如使用 Spring 进行测试时可以指定 @RunWith(SpringRunner.class)
;@BeforeEach
:在每个测试方法之前运行的方法(JUnit 5);@AfterEach
:在每个测试方法之后运行的方法(JUnit 5);@ParameterizedTest
:参数化测试方法(JUnit 5)。注解在这些框架中广泛应用,通过提供特定的注解,开发者可以方便地实现配置、路由、依赖注入、持久化等相关功能,大大简化了开发过程。同时,注解也为框架提供了更好的扩展性和灵活性。
Java注解提供了一种简洁、灵活和强大的方式来为代码添加额外的元数据信息。它们能够提高代码的可读性、可维护性和健壮性。尽管有一些缺点,但合理地使用注解将带来很多好处。随着时间的推移,注解已经成为许多流行框架和库的核心组成部分。