Java Annotation详解(一): 理解和使用Annotation
JDK1.5之后,引入了元数据的概念,也就是Annotation(注释),其实它是代码里的特殊标记,这些标记可以再编译、类加载、运行时被读取,并执行相应的处理。
元数据的作用:
如果要对于元数据的作用进行分类,目前还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:
1. 编写文档:通过代码里标识的元数据生成文档。
2. 代码分析:通过代码里标识的元数据对代码进行分析。
3. 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
一、 系统内建的Annotation:
@Override 覆写的Annotation
注释能实现编译时检查,你可以为你的方法添加该注释,以声明该方法是用于覆盖父类中的方法。如果该方法不是覆盖父类的方法,将会在编译时报错。例如我们为某类重写toString()方法却写成了tostring(),并且我们为该方法添加了@Override注释,则会提示编译错误。
@Deprecated 不赞成使用的Annotation
其作用是对不应该在使用的方法添加注释,当编程人员使用这些方法时,将会在编译时显示提示信息,不推荐在使用该方法或该类。
@SuppressWarnings 压制安全警告的Annotation
与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:
deprecation 使用了过时的类或方法时的警告
unchecked 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型
fallthrough 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告
path 在类路径、源文件路径等中有不存在的路径时的警告
serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告
finally 任何 finally 子句不能正常完成时的警告
all 关于以上所有情况的警告
在为@SuppressWarnings设置注释信息的时候,是以key-value的形式出现的,所以以上的@SuppressWarnings也可以直接使用,所以@SuppressWarnings可以使用”value={"unchecked","deprecation"}“的方式来设置。
@Deprecated
class Demo<T>{
private T var ;
public T getVar(){
return this.var ;
}
public void setVar(T var){
this.var = var ;
}
};
public class SuppressWarningsAnnotationDemo03{
// @SuppressWarnings(value={"unchecked","deprecation"})
public static void main(String args[]){
Demo d = new Demo() ;
d.setVar("沉缘") ;
System.out.println("内容:" + d.getVar()) ;
}
};
上面,我们将 注释掉,编译后,会出现警告提示:
---------- javac ----------
注: SuppressWarningsAnnotationDemo03.java使用或覆盖了已过时的 API。
注: 有关详细信息, 请使用 -Xlint:deprecation 重新编译。
注: SuppressWarningsAnnotationDemo03.java使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。
打开@SuppressWarnings注释,再次编译,发现,警告已被抑制。
二、 自定义Annotation
定义简单的Annotation形式:
[public] @interface Annotation名称{
数据类型 变量名称();
}
例如:
public @interface MyDefaultAnnotationNoneParam{
}
之后,就可以直接使用@Annotation名称:
@MyDefaultAnnotationNoneParam
class Demo
{
}
此时,就表示在Demo类上使用Annotation。
还可以向Annotation中设置变量,使用变量接受参数。
public @interface MyDefaultAnnotationSingleParam{
public String value(); //接受设置的参数
}
在使用的时候,必须清楚的指定变量的名称,变量的内容:
@MyDefaultAnnotationSingleParam("沉缘")
class Demo
{
}
或者使用明确的标记,表示内容赋给哪个参数:
@MyDefaultAnnotationSingleParam(value="沉缘")
class Demo
{
}
以上的参数,是要赋给value属性的。既然可以设置一个参数,则也就可以同时设置多个参数。
public @interface MyDefaultAnnotationMoreParam{
public String key() ;
public String value() ; // 接收设置的内容
}
此Annotation在使用时,需要设置两个参数,一个key,一个value。
@MyDefaultAnnotationMoreParam(key="Linkage",value="沉缘")
class Demo{
};
当然,我们可以设置数组进去,@SuppressWarnings就使用了数组。
public @interface MyDefaultAnnotationArrayParam{
public String[] value() ; // 接收设置的内容
}
接收内容本身是一个数组类型,要传递数组。
@MyDefaultAnnotationArrayParam(value={"沉缘","流烬"})
class Demo{
};
以上的定义Annotation都未指定属性的默认值,必须在使用时设置。 其实,也可以直接使用default来定义默认值:
public @interface MyDefaultAnnotationValue{
public String key() default "Linkage" ; // 指定好了默认值
public String value() default "沉缘" ; // 指定好了默认值
}
在实际的操作中,对于一个Annotation而言,有时候会固定其取值范围,只能使用固定的几个值。那么这时候实际上就需要依靠枚举:
public enum MyName{ // 定义枚举类型
WUQING,WUYUAN,WULEI ;
} public @interface MyDefaultAnnotationEnum{
public MyName name() default MyName.WUQING ; // 指定默认值
}
三、 限定注释使用范围Target
当我们的自定义注释不断的增多也比较复杂时,就会导致有些开发人员使用错误,主要表现在不该使用该注释的地方使用。为此,Java提供了一个ElementType枚举类型来控制每个注释的使用范围,比如说某些注释只能用于普通方法,而不能用于构造函数等。下面是Java定义的ElementType枚举:
package java.lang.annotation; public enum ElementType { TYPE, // Class, interface, or enum (but not annotation) FIELD, // Field (including enumerated values) METHOD, // Method (does not include constructors) PARAMETER, // Method parameter CONSTRUCTOR, // Constructor LOCAL_VARIABLE, // Local variable or catch clause ANNOTATION_TYPE, // Annotation Types (meta-annotations) PACKAGE // Java package }
想要使用ElementType,只需要为注释添加@Target即可:
@Target( { ElementType.METHOD, ElementType.CONSTRUCTOR }) public @interface TargetTest { }
正如上面代码所展示的,我们只允许Greeting注释标注在普通方法和构造函数上,使用在包申明、类名等时,会提示错误信息。
四、 Retention和RetentionPolicy,注释保持性策略
public enum RetentionPolicy { SOURCE,// Annotation is discarded by the compiler CLASS,// Annotation is stored in the class file, but ignored by the VM RUNTIME// Annotation is stored in the class file and read by the VM }
RetentionPolicy的使用方法的简单代码示例如下:
@Retention(RetentionPolicy.RUNTIME)
而,在RetentionPolicy的三个范围中,最需要注意的就是RUNTIME范围,因为在执行的时候起作用。
import java.lang.annotation.Retention ;
import java.lang.annotation.RetentionPolicy ;
@Retention(value=RetentionPolicy.RUNTIME) // 表示此Annotation在运行时有效
public @interface MyDefaultRententionAnnotation{
public String name() default "沉缘" ;
}
我们看下内建的Annotation的RetentionPolicy:
@Override定义采用的是@Retention(value=SOURCE),只能在源文件中出现。
@Deprecated定义采用的是@Retention(value=RUNTIME),可以在执行时出现。
@SuppressWarnings定义采用的是@Retention(value=SOURCE),只能在源文件中出现。
五、 文档化功能
Java提供的Documented元注释跟Javadoc的作用是差不多的,其实它存在的好处是开发人员可以定制Javadoc不支持的文档属性,并在开发中应用。它的使用跟前两个也是一样的,简单代码示例如下:
import java.lang.annotation.Documented ;
@Documented
public @interface MyDocumentedAnntation{
<span style="white-space:pre"> </span>public String key() default "Linkage" ;
<span style="white-space:pre"> </span>public String value() default "沉缘" ;
}
成功后,在使用此Annotation的时候,可以增加一些信息进去:
@MyDocumentedAnntation(key="Baidu",value="www.baidu.com")
public class SimpleBeanDocumented{
/**
* 此方法在对象输出时调用,返回对象信息
*/
@MyDocumentedAnntation(key="Xinlang",value="www.sina.com")
public String toString(){
return "Hello World!!!" ;
}
};
之后,在生成jdk文档的时候,使用@Document修饰的方法将被注释下来。
六、 标注继承
继承应该是Java提供的最复杂的一个元注释了,它的作用是控制注释是否会影响到子类(一个Annotation是否可以被继承下来),简单代码示例如下:
package com.test.inheriteddemo ;
import java.lang.annotation.Retention ;
import java.lang.annotation.RetentionPolicy ;
import java.lang.annotation.Documented ;
import java.lang.annotation.Inherited ;
@Documented
@Inherited
@Retention(value=RetentionPolicy.RUNTIME)
public @interface MyInheritedAnnotation{
public String name() ; }
使用该注释,标注一个父类Person:
package com.test.inheriteddemo ;
@MyInheritedAnnotation(name="沉缘")
public class Person{
};
按照所解释的,使用Inherited声明的Annotation是可以被子类继承下来的:
import java.lang.annotation.Annotation ;
import org.lxh.demo16.inheriteddemo.MyInheritedAnnotation ;
public class ReflectInheritedDemo{
public static void main(String args[]) throws Exception{
Class<?> c = null ;
c = Class.forName("com.test.inheriteddemo.Student") ;
Annotation ann[] = c.getAnnotations() ; // 取得全部的Annotation
for(Annotation a:ann){ // 输出
System.out.println(a) ;
}
// 继续取得此Annotation设置的内容
if(c.isAnnotationPresent(MyInheritedAnnotation.class)){
MyInheritedAnnotation mda = null ;
mda = c.getAnnotation(MyInheritedAnnotation.class) ;
String name = mda.name() ; // 取出name的内容
System.out.println("name = " + name) ;
}
}
}
Java Annotation详解(一): 理解和使用Annotation的更多相关文章
- Java Annotation详解 理解和使用Annotation
系统中用到了java注解: 查了一下如何使用注解,到底注解是什么: (1)创建方法:MsgTrace Java Class==> 在Create New Class中: name:输入MsgTr ...
- Java Annotation详解(二): 反射和Annotation
前面一篇文<Java Annotation详解(一): 理解和使用Annotation>中,我们或许会觉得,Annotation注释其实并没有多大的作用,除了几个内建的Annotation ...
- Java注解(Annotation)详解
转: Java注解(Annotation)详解 幻海流心 2018.05.23 15:20 字数 1775 阅读 380评论 0喜欢 1 Java注解(Annotation)详解 1.Annotati ...
- Java内部类详解
Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...
- Java虚拟机详解----JVM常见问题总结
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...
- [转] Java内部类详解
作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...
- Java面向对象详解
Java面向对象详解 前言:接触项目开发也有很长一段时间了,最近开始萌发出想回过头来写写以前学 过的基础知识的想法.一是原来刚开始学习接触编程,一个人跌跌撞撞摸索着往前走,初学的时候很多东西理解的也懵 ...
- java 乱码详解_jsp中pageEncoding、charset=UTF -8"、request.setCharacterEncoding("UTF-8")
http://blog.csdn.net/qinysong/article/details/1179480 java 乱码详解__jsp中pageEncoding.charset=UTF -8&quo ...
- Java synchronized 详解
Java synchronized 详解 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 1.当两个并发线程访问同一个对象object ...
- 【转】Java内部类详解
一.内部类基础 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.广泛意义上的内部类一般来说包括这四种:成员内部类.局部内部类.匿名内部类和静态内部类.下面就先来了解一 ...
随机推荐
- 威胁快报|Nexus Repository Manager 3新漏洞已被用于挖矿木马传播,建议用户尽快修复
背景 近日,阿里云安全监测到watchbog挖矿木马使用新曝光的Nexus Repository Manager 3远程代码执行漏洞(CVE-2019-7238)进行攻击并挖矿的事件. 值得注意的是, ...
- 缺氧debug模式开启及功能
在游戏OxygenNotIncluded_Data文件夹创建一个debug_enable.txt的空文本文档 在缺氧目录下添加debug_enable.txt文件 按删除键就可以开启debug模式 需 ...
- UML时序图(Sequence Diagram)学习笔记
什么是时序图时序图(Sequence Diagram),又名序列图.循序图,是一种UML交互图.它通过描述对象之间发送消息的时间顺序显示多个对象之间的动态协作. 让我们来看一看visio2016对时序 ...
- django1.11启动错误
错误信息: 复制代码 Unhandled exception in thread started by <function check_errors..wrapper at 0x10f03b8c ...
- 扩展 Microsoft.Owin.Security
微软在 OWIN 框架中对 OAuth 认证的支持非常好, 使用现有的 OWIN 中间件可以做到: 使用 Microsoft.Owin.Security.OAuth 搭建自己的 OAuth2 服务端, ...
- 7 种 Javascript 常用设计模式学习笔记
7 种 Javascript 常用设计模式学习笔记 由于 JS 或者前端的场景限制,并不是 23 种设计模式都常用. 有的是没有使用场景,有的模式使用场景非常少,所以只是列举 7 个常见的模式 本文的 ...
- day38 13-Spring的Bean的属性的注入:SpEL注入
Spring2.5提供了名称空间p注入属性的方式,Spring3.几提供了SpEL属性注入的方式. <?xml version="1.0" encoding="UT ...
- python的解释器类型
Python解释器 当我们编写Python代码时,我们得到的是一个包含Python代码的以.py为扩展名的文本文件.要运行代码,就需要Python解释器去执行.py文件. 由于整个Python语言从规 ...
- 非接触型手掌静脉识别 PalmSecure™
静脉识别,使用近红外线读取静脉模式,与存储的静脉模式进行比较,进行本人识别的识别技术.富士通的PalmSecure™,利用该技术,由离开识别装置的位置,使用近红外线拍摄,与预先存储的静脉模式进行比较从 ...
- Python编码---转自金角大王
本节内容 编码回顾 编码转换 Python的bytes类型 编码回顾 在备编码相关的课件时,在知乎上看到一段关于Python编码的回答 这哥们的这段话说的太对了,搞Python不把编码彻底搞明白,总有 ...