Java 注解的简介

本文围绕Java注解展开,介绍了注解的含义、特性、作用域等基本概念,阐述了元注解如@Inherited、@Documented等的功能。还讲解了自定义注解的定义与使用,通过最佳实践展示了@Documented效果、反射获取注解、设置切点及在Spring拦截器中的应用,辨析了不同保留阶段注解的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

Java 1.5 引入了注解(annotations)

注解的含义和几个问题

注解,顾名思义,是一种的标注,在实际的使用中要注意注解的四个特性
注解被用于什么地方,类、方法、注解?
被注解修饰的类或者方法是否会体现在 Java 文档中?
注解的可见性,源码可见、class文件可见、运行期可见?
注解是否能被子类继承?

注解的作用域

作为注解,其最为重要的一个作用是起到方便理解代码含义,所以注解本身并非一定要有什么作用的。单从查看注解的角度来看,注解可以分为源码阶段可见、编译阶段可见和运行阶段可见。

注解是否展示在 Java 帮助文档中?

作为注解,其被使用在类或者方法上时,有时候是有必要让阅读 Java 帮助文档的人看到的,你可以通过 javadoc 命令来做测试

注解被用于什么地方?

注解可以被用于方法上、类上、接口上、其他注解的定义上

元注解

元注解即定义注解的注解,元注解有 @Documented、@Target、@Retention、@Inherited

@Inherited

如果定义注解时使用了 @Inherited 标记,然后用定义的注解来标注另一个父类, 父类又有一个子类(subclass),则父类的所有属性将被继承到它的子类中.

@Documented

注解定义使用@Documented,表示 javadoc 命令生成的文档中将显示本注解的标注内容

@Target

@Target(ElementType.METHOD)//指定注解可以被标注的位置,错误的报错会导致IDE报错

@Retention

@Retention 的使用需要结合 RetentionPolicy。形式如 @Retention(RetentionPolicy.SOURCE)

注解保留的阶段描述

  • RetentionPolicy.SOURCE —— 注释只在源代码级别保留,编译时被忽略,比如 @Override 这个注解
  • RetentionPolicy.CLASS —— 注释将被编译器在类文件中记录但在运行时不需要JVM保留。这是默认的行为
  • RetentionPolicy.RUNTIME —— 注释将被编译器记录在类文件中在运行时保留VM,因此可以反读
自己写注解
定义一个注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Inherited
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnonation {
	String name() default {};//在使用本注解时可以添加额外信息
}
自定义注解的使用
public class TestA {
	@MyAnnonation(name="1")
	public void test(){
	}
}
最佳实践
@Documented 的效果

javadoc 命令生成说明文档
MyAnnonation 的 @Documented被注释的话

在这里插入图片描述

MyAnnonation 的 @Documented被保留且 TestA 使用该注解@MyAnnonation(name=“1”)

在这里插入图片描述

利用反射方法获取注解

这里是获取方法上的注解

import org.junit.Test;
import java.lang.reflect.Method;

public class TestATest {

    @Test
    public void test(){
        TestA testA=new TestA();
        try{
            Method m=TestA.class.getMethod("test");
            MyAnnonation myAnnonation=m.getAnnotation(MyAnnonation.class);
            if(myAnnonation!=null){
                System.out.println("通过反射机制获取到了方法上的注解");
            }
        }catch(NoSuchMethodException e){
            //TODO 反射方法不存在异常
        }
    }
}
为注解设置切点

自定义注解后为注解设置切点,然后可以采取其他操作

@Pointcut("@annotation(包路径.MyAnnonation)")
    public void MyAnnonationAspect() {
    }
Spring 拦截器中注解的应用
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

public class MyHandlerInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(MyAnnonation.class)){//这是重点
            //表示该方法被 注解 @MyAnnonation 修饰了
        }
        return true;
    }
    //略其他方法
}
@Target(RetentionPolicy.SOURCE)、@Target(RetentionPolicy.CLASS ) 的辨析

从一般角度来看,@Target(RetentionPolicy.RUNTIME)注解可以使我们的代码在运行期通过反射获得注解,但是 @Target(RetentionPolicy.SOURCE)、@Target(RetentionPolicy.CLASS )都无法为我们提供更多的功能
关于这个问题,我摘取了网上的一段评论
“源代码级别的注解有两个意图,
一是作为文档的补充, 给人看的, 比如@Override注解、@SuppressWarnings注解,
二是作为源代码生成器(java和android都有注解处理器APT)的材料,
比如ButterKnife框架.同样字节码级别的注解, 可以作为字节码修改, 插桩, 代理的依据,
可以使用aspectj, asm等工具进行字节码修改.
比如一些模块间调用, 如果你直接写代码, 会导致耦合,
此时可以加入一个注解, run一下asm这样的工具,
将注解标注的方法字段以generate的方式插入进去.
运行时级别的注解, 显然是用于反射后参与某些业务逻辑用的, 比如spring依赖注入”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值