java 自定义警告_java中如何自定义注解

作为一名开发人员,注解的的使用是最常见的了,比如Spring框架里的业务层注解@Service、@Transaction,控制层用的@Controller、@Autowired,SpringBoot框架的启动类注解@SpringBootApplication等等。那么如何自定义注解呢?

一、什么是注解

注解(Annotation)是元数据的一种形式,从JDK5.0 引入,它能为代码提供一些相关数据,以便于在代码编译或运行时使用。

二、注解的作用

Java中的注解可以修饰类、方法、变量、参数等。注解可以通过反射手段获取其内容,在编译器生成类文件时,注解可以被嵌入到字节码中。当然JVM也可以保留注解的内容,在运行时动态,总结起来主要是以下几个层面:

编译器根据注解在编译代码时行进行提示警告或错误信息

例如我们在使用java.util包下的Date类时,调用了类中被@Deprecated标注的方法,IDE会在编译时会有警告信息

public static void main(String[] args){

Date date = new Date();

//JDK源码中,Date类的getDay方法被@Deprecated注解标注,代表方法已过时

int day = date.getDay();

}

复制代码编译运行时时根据注解动态生成代码

例如在springboot框架中,我们实现一个Controller层方法的前置通知,通过使用@Aspect、@Before等注解即可,当然这些注解是框架封装好的,屏蔽了底层的细节,但是AOP的原理,大家应该都很熟悉

@Slf4j

@Component

@Aspect

public class MyAspect{

@Before(value = "execution(public * com.test.controller.*.*(..))")

public void before(JoinPoint joinPoint){

log.info("CLASS_METHOD:[{}]" , joinPoint.getSignature().getName());

}

}

复制代码程序运行时使用注解进行动态赋值

比如通过使用@Value注解,将配置文件参数赋给代码里面变量,例如SpringBoot里面集成RabbitMq时,账户密码等配置信息通过注解进行配置

@Configuration

public class RabbitMqConfig{

@Value("${spring.rabbitmq.host}")

private String rabbitMqHost;

@Value("${spring.rabbitmq.port}")

private String rabbitMqPort;

}

复制代码

三、自定义注解

首先我们先看下一个注解示例,下面是javafx.beans包下的@DefaultProperty注解 :

package javafx.beans;

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;

/**

* Specifies a property to which child elements will be added or set when an

* explicit property is not given.

*

* @since JavaFX 2.0

*/

@Inherited

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)

public @interface DefaultProperty {

/**

* The name of the default property.

*/

public String value();

}

复制代码

我们看到定义注解与定义一个class类相似,不过其中class关键字被替换为了@interface,注解里声明了一个String类型的value属性,注意这种声明属性方式!稍后会详细说明。同时还可以看到DefaultProperty注解被@Inherited、@Documented、@Retention(RetentionPolicy.RUNTIME)、@Target(ElementType.TYPE)这些注解所修饰,这就是我们需要知道另外一个概念——元注解(meta-annotations)。

1.元注解

元注解是我们在定义注解时需要用到的一些特殊含义的注解,可以说它们是对声明注解时的注解。java语言为我们默认提供了以下元注解,在java.lang.annotation包下,我们来看下:

@Retention(RetentionPolicy.XX) 注解的保留域,表示注解的保留范围,可选项有

RetentionPolicy.SOURCE – 源代码级别保留,编译器编译后该类型的注解就被丢弃掉了,生成的.class字节码文件中,将不再存在该类型的注解.

RetentionPolicy.CLASS – .class字节码文件中保留,编译器编译后保留,JVM加载后丢弃掉,运行时无法获取

RetentionPolicy.RUNTIME – 运行时保留,在运行时,JVM使用反射,可以获取注解属性内容,绝大多数注解在定义是使用都是该级别

@Target( ElementType.XX) 指定该注解可以使用的地方,如类声明、方法声明,变量声明等等, 在定义注解时,如果没有使用Target指定,默认都可以使用。如果使用了Target指定使用的位置,那么该注解只能在所指定的位置使用

ElementType.ANNOTATION_TYPE 注解类型声明

ElementType.CONSTRUCTOR 构造方法

ElementType.FIELD 字段声明(包括枚举常量)

ElementType.LOCAL_VARIABLE 局部变量声明

ElementType.METHOD 方法声明

ElementType.PACKAGE 包声明

ElementType.PARAMETER 方法的参数声明

ElementType.TYPE 类、接口(包括注解类型)或enum声明

@Documented 表示在使用Javadoc工具生成文档时,包含此注解信息

@Inherited 表示当前注解是可继承的,父类中所使用的注解如果被@Inherited修饰,子类会继承父类中对应的注解

2.注解属性定义方式

明白了注解的外在定义形式,那么我们就来看下注解内部的属性的定义方式,Talk is cheap. Show me the code 多说无益,直接上代码

@Documented

@Inherited

@Target({ElementType.METHOD})

@Retention(RetentionPolicy.RUNTIME)

public @interface MyAnnotation {

/**

*1、属性的定义和接口中方法声明类似,访问修饰符默认是public,可省略,注意属性名后面跟了()

*/

String name();

/**

* 2、可以通过default为属性指定默认值,在注解使用时,可以为之赋值, 也可以不赋值

* 当然如果不通过default为属性指定默认值,在注解使用必须使用该属性并且为之赋值

*/

int age() default 1;

/**

* 3、注解中的属性value比较特殊,如果使用注解时仅为该属性赋值,"value="可以省略掉,

* 但是如果和其他属性同时赋值,“value=”则不能省略,这个特性和value的属性类型无关

*/

String value() default "";

/**

* 4.注解中属性的类型可以是基本数据类型及其数组、类、枚举、注解

*/

boolean sex() default true;

}

复制代码

四、通过反射获取注解属性值

在上面代码中,我们自定义了@MyAnnotation注解,并且指明@Target({ElementType.METHOD})表明此注解只能用在方法声明上, @Retention(RetentionPolicy.RUNTIME)指定其保留到代码运行时,所以我们可以通过反射获取MyAnnotation的属性值。下面我们定义了一个Person类,并在其中定义了一个sayHello方法,在方法声明上,我们使用@MyAnnotation注解,我们将使用反射调用sayHello方法,并且使用MyAnnotation注解中的属性值

package com.test.annotation;

import com.test.enu.Color;

import java.lang.annotation.Annotation;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class Person{

@MyAnnotation(name="韩梅梅",age = 30,sex = true,clothes = Color.YELLOW)

public void sayHello(String name){

System.out.println("Hello!" + name);

}

public static void main(String[] args) throws InvocationTargetException, IllegalAccessException{

Person person = new Person();

//获取Person类的Class对象

Class extends Person> personClass = person.getClass();

//获取类中声明的方法列表

Method[] declaredMethods = personClass.getDeclaredMethods();

for (Method method : declaredMethods) {

//判断当前方法是否含有MyAnnotation注解

if(method.isAnnotationPresent(MyAnnotation.class)){

//获取MyAnnotation类型注解

MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);

//反射调用方法,并传递注解name属性值为参数

Object invoke = method.invoke(person,myAnnotation.name());

//打印注解中定义的各个类型的值

System.out.println(myAnnotation);

System.out.println(myAnnotation.name()+","+myAnnotation.sex()+","+myAnnotation.age());

}

}

}

}

复制代码

此时的IDE控制台输出,说明我们通过反射在运行时获取到了@MyAnnotation注解的值

Hello!韩梅梅

韩梅梅,true,30

@com.test.annotation.MyAnnotation(value=, age=30, sex=true, name=韩梅梅, clothes=YELLOW)

复制代码

五、JDK内部自带注解

JDK自带了一些原先定义好的注解,我们可以直接使用

@Override 表示当前方法覆盖了父类的方法

@Deprecation 表示方法已经过时,方法上有横线,使用时会有警告。

@SuppviseWarnings 表示关闭一些警告信息(通知java编译器忽略特定的编译警告)

至于注解内部详细内容,大家可以点进去源码查看。希望本篇文章对你有所帮助!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值