java注释和注解_深入理解JAVA注解(Annotation)以及自定义注解

Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。Java 语言中的类、方法、变量、参数和包等都可以被标注。注解可以看作是一种特殊的标记,在程序在编译或者运行时可以检测到这些标记而进行一些特殊的处理。本文对 Annotation 进行了整理带你一步一步解开Java注解的神秘面纱并实现自己的自定义注解。

元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。他们位于java.lang.annotation包中。

元注解下

@Target

@Retention

@Documented

@Inherited

@Target:

源码如下

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Target {

/**

* Returns an array of the kinds of elements an annotation type

* can be applied to.

* @return an array of the kinds of elements an annotation type

* can be applied to

*/

ElementType[] value();

}

它表明该注解可以应用的java元素类型

ElementType.TYPE:应用于类、接口(包括注解类型)、枚举

ElementType.FIELD:应用于属性(包括枚举中的常量)

ElementType.METHOD:应用于方法

ElementType.PARAMETER:应用于方法的形参

ElementType.CONSTRUCTOR:应用于构造函数

ElementType.LOCAL_VARIABLE:应用于局部变量

ElementType.ANNOTATION_TYPE:应用于注解类型

ElementType.PACKAGE:应用于包

ElementType.TYPE_PARAMETER:1.8版本新增,应用于类型变量)

ElementType.TYPE_USE:1.8版本新增,应用于任何使用类型的语句中(例如声明语句、泛型和强制转换语句中的类型)

@Retention:源码如下

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Retention {

/**

* Returns the retention policy.

* @return the retention policy

*/

RetentionPolicy value();

}

它需要在什么级别保存该注释信息,用于描述注解的生命周期

RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),编译时被丢弃,不包含在类文件中

RetentionPolicy.CLASS:在class文件中有效(即class保留),JVM加载时被丢弃,包含在类文件中,默认值

RetentionPolicy.RUNTIME:在运行时有效(即运行时保留),由JVM 加载,包含在类文件中,在运行时可以被获取到

@Documented:

源码如下

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Documented {

}

它表明该注解标记的元素可以被Javadoc或类似的工具文档化,@Documented是一个标记注解,没有成员。

@Inherited源码如下

@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.ANNOTATION_TYPE)

public @interface Inherited {

}

表明使用了@Inherited注解的注解,所标记的类的子类也会拥有这个注解是不是有点难以理解,我们举个例子

自定义注解

自定义注解 @InheritedTest

package com.example.demo.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Inherited public @interface InheritedTest {

}

新建父类 Parent

package com.example.demo.test;

import com.example.demo.annotation.InheritedTest;

@InheritedTest

public class Parent {

public void testMethod(){

System.out.println("Parent " + Parent.class.isAnnotationPresent(InheritedTest.class));

}

}

新建子类 Child

package com.example.demo.test;

import com.example.demo.annotation.InheritedTest;

public class Child extends Parent {

public static void main(String[] args) {

Child child = new Child();

child.testMethod();

System.out.println("Child " + Child.class.isAnnotationPresent(InheritedTest.class));

}

}

isAnnotationPresent()方法表示指定注释类型的注释是否存在于此元素上,是则返回true,否则返回false。

我们运行子类可以看到如下结果

64981377d67a3f98e2f5c3c4927cb299.png

在子类中我们并没有使用 @InheritedTest 注解,结果一样返回了true,下面我们把InheritedTest中的@Inherited注释掉,然后再运行子类结果如下

fac0f8c08c0697e0adc8c4ceae350941.png

可以看到,现在返回了false。

简单示例

package com.example.demo.annotation;

import java.lang.annotation.*;

@Target(ElementType.FIELD)

@Documented()

@Retention(RetentionPolicy.RUNTIME)

public @interface Color {

String value() default "";

}

以上我们就自定义了一个注解@Color,该注解应用于属性之上,在运行时有效,并且可以生成api文档。使用方法

package com.example.demo.test;

import com.example.demo.annotation.Color;

public class Cat {

@Color("黄色")

private String color;

public String getColor(){

return this.color;

}

public void setColor(String color){

this.color = color;

}

public static void main(String args[]){

Cat cat = new Cat();

System.out.println(cat.getColor());

}

}

这里我们定义了一个Cat类,里面有一个属性color,我们使用@Color(“黄色”)给他赋值为黄色,然后执行这个类打印出结果如下

8fe232b3bd096672a73ba8953440c1b8.png

什么?怎么为null呢,是不是感觉被忽悠了?因为我们只是定义了这个注解,但是却没写怎么处理被这个注解标记了字段,这个时候打印出来的当然为null了。

现在我们来修改一下Cat类

public static void main(String args[]) throws NoSuchFieldException {

Cat cat = new Cat();

Color color = Cat.class.getDeclaredField("color").getAnnotation(Color.class);

if (color != null) {

String value = color.value();

cat.setColor(value);

}

System.out.println(cat.getColor());

}

打印结果如下

259e3f60d7cc303231f38be1f52be6e8.png

以上我们简单的处理了下注解,并把处理逻辑放在了main方法中,其实这是不合理的。我们通过用下面的例子,使用Spring AOP面向切面编程思想来自定义日志注解。

自定义注解

自定义日志注解@SysLog

package com.example.demo.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)

@Documented()

@Retention(RetentionPolicy.RUNTIME)

public @interface SysLog {

String value() default "";

}

定义切面

package com.example.demo.aspect;

import com.example.demo.annotation.SysLog;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;

import org.aspectj.lang.reflect.MethodSignature;

import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect

@Component

@Slf4j

public class SysLogAspect {

@Pointcut("@annotation(com.example.demo.annotation.SysLog)")

private void logPointCut() {

}

@Before("logPointCut()")

private void before(JoinPoint joinPoint){

String className = joinPoint.getTarget().getClass().getName();

MethodSignature signature = (MethodSignature) joinPoint.getSignature();

String methodName = signature.getName();

Method method = signature.getMethod();

SysLog sysLog = method.getAnnotation(SysLog.class);

String value = sysLog.value();

log.info(className);

log.info(methodName);

log.info(value);

log.info("这里我们就可以自己处理了");

}

@After("logPointCut()")

private void after(){

log.info("执行之后");

}

}

测试注解

package com.example.demo.test;

import com.example.demo.annotation.SysLog;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController @RequestMapping("/log")

public class LogTest {

@SysLog("测试日志打印")

@RequestMapping("/test")

public String testLog(){

return "这里是测试自定义注解日志打印";

}

}

用postman访问localhost:8080/log/test结果如下

4084a01e6910955c89d3407f7a197028.png

控制台日志打印如下

1992754f8595960023dbc312e67233fc.png

以上我们就完成了自定日志注解的实现,以上例子只是示例,实际开发中还可以又更多功能实现。好了,本文介绍就到这里了,如有错误请提出指正。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/409058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[机器学习笔记]Note10--支持向量机(SVM)

继续是机器学习课程的笔记,这节课的内容是介绍支持向量机(SVM)的内容。SVM是一个非常强大且流行的算法,在一些情况下,面对一些复杂的非线性问题可以提供比逻辑回归或神经网络更加简洁更加有效的结果。 优化目标 首先…

[机器学习笔记]Note11--聚类

继续是机器学习课程的笔记,本节介绍的是聚类方法,主要是K-means算法。 非监督学习 首先介绍监督学习和非监督学习的区别。一个监督学习的例子如下图,给定训练集如:{(x(1),y(1)),(x(2),y(2)),…,(x(m),y(m))},每个训练实例都有对应的标签。 …

[机器学习笔记]Note12--降维

继续是机器学习课程的笔记,本节介绍的是降维方法,这也是非监督学习中的一个问题,主要介绍主要成分分析(Principal Component Analysis,PCA)算法。 降维 动机一:数据压缩 使用降维的一个原因是…

[机器学习笔记]Note13--异常检测

继续是机器学习课程的笔记,本节课内容是异常检测,它是一个非监督学习算法,用于发现可能不应该属于一个已定义的组中的数据。 密度估计 首先是给出一个例子,如下图所示,是一个测试飞机引擎的例子,给定数据…

[机器学习笔记]Note14--推荐系统

继续是机器学习课程的笔记,本节课将介绍推荐系统的内容。 问题形式化 推荐系统是机器学习的一个非常重要的应用,在很多音乐、购物等网站都有推荐系统,如豆瓣,淘宝,网易云音乐等都是有使用到推荐系统的,因…

[机器学习笔记]Note15--大规模机器学习

继续是机器学习课程的笔记,本节内容主要是介绍大规模机器学习的内容。 大型数据集的学习 对于一个过拟合的模型,增加数据集的规模可以帮助避免过拟合,并获得一个更好的结果。 但是对于一个大规模的数据,比如有100万个数据量的训…

[机器学习笔记]Note16--应用示例:图像文字识别

继续是机器学习课程的笔记,本节课是最后一节内容了,主要是介绍一个应该–图中文字的识别。 问题描述和流程图 图像文字识别应用就是从给定的图片中识别文字。这比从一份扫描文档中识别文字要复杂得多。一个例子图片如下所示: 为了完成这样的…

python小老鼠编程_邯郸pythonnot学习费用多少

邯郸pythonnot学习费用多少更新时间:2020-08-02 12:49:04注意:如果出现错误,可能是因为安装时未勾选AddPython3.5toPATH选项,此时卸载Python后重新安装时勾选AddPython3.5toPATH选项即可。1.2Mac中安装Python3Mac系统中自带了Pyth…