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))},每个训练实例都有对应的标签。 …

LLVM每日谈之十二 LLVM的源码分析之Pass相关

作者:snsn1984题记:在学习LLVM的过程中,要想学的更加深入,掌握更多的技能,LLVM的源码是必须要读的,但是在这么多的源码中,从哪里下手?很容易让人找不到头脑,本文这里就先…

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

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

jetty java 实例_Maven+Jetty+Servlet 简单示例

一个朋友让我帮他写一个基于 Servlet JettyDerby 实现的项目。本文先介绍 MavenJettyServlet 的整合例子。1、添加依赖pom.xml 里添加依赖javax.servletjavax.servlet-api3.1.0org.eclipse.jetty9.4.14.v20181114jetty-webapp2、准备两个 Servlet 例子HelloServletpackage com.…

节后的人才市场开始活跃了?

今天居然接到一个印度打来的电话,一印度MM操着纯正的印度英语居然说是从Linkedin上找到我的,希望我能参加他们杭州公司的面试,费了很大的劲也没让她弄明白我不愿意relocate。 只能说节后的人才市场就像快烧开的水,分子们开始活跃了…

mysql 静态表 是不是 myisam_mysql的静态表和动态表的区别,MyISAM和InnoDB的区别

静态表字段长度固定,自动填充,读写速度很快,便于缓存和修复,但比较占硬盘,动态表是字段长度不固定,节省硬盘,但更复杂,容易产生碎片,速度慢,出问题后不容易重…

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

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

html5新增元素

一、HTML5新增结构元素 之前,我们只能用万能的div标签,并为其设置不同的id如header, footer, sidebar等来分别表达头部,底部或者侧栏等。而现在代码编写者不再需要为id的命名费尽心思,对于手机、阅读器等设备更有语义的好处。 HTM…

python 代码转程序_精悍的Python代码段-转

1 文件处理readlines() 和 writelines()方法可以讲列表元素依次写到文件中;file类本身没有提供复制方法,可以使用read()和write()方法模拟实现文件的拷贝,也可以使用shutil模块:shutil.copyfile(hello.txt,hello2.txt)shutil.move…

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

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

手机应用开发的方式不能完全套用到iPad上

对于一些复杂的游戏,许多人已经不能满足于手机小巧的屏幕,大屏的画面感就成为许多人选择平板电脑的重要因素。当越来越多的80后开始为人父母,孩子们从大人手中得到的礼物,也不再局限于零食、玩具和游乐场入场券。随着智能手机的普…

java面向对象编程思想_Java面向对象编程思想

面向对象三个特征:封装、继承、多态封装:语法:属性私有化(private)、提供相对应的get/set 的方法进行访问(public)、在set/get的方法中对属性的数据 做相对应的业务逻辑的判断思想:封装外面的程序不能直接访问本类的属性&#xff…

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

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