Java高级特性 第6节 注解初识
一、注解概述
Java注解也就是Annotation,是Java代码里的特殊标记,它为Java程序代码提供了一种形式化的方法,用来表达额外的某些信息,这些信息是代码本身无法表示的。
注解以标签的形式存在于代码之中,注解的存在并不影响代码程序的编译执行,它只是用来生成其他的文件或使我们在运行代码时知道被运行代码的描述信息。
注解的语法格式:@Annotation(参数)
- 将注解置于所有修饰符之前;
- 通常将注解单独放在一行;
- 默认情况下,注解可以用于修饰任何程序元素,包括类、方法和成员变量等;
二、注解分类
Java中根据注解的作用和使用方法,可以分为3类:内建注解、元注解、自定义注解。
注解很重要,未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,现在的Struts2有一部分也是基于注解的了,注解是一种趋势,现在已经有不少的人开始用注解了。
1. 内建注解
注解是JDK1.5之后才有的新特性,JDK1.5版本的java.lang包下提供了3中标准的注解类型:
- @Override 被用来标注方法,表示该方法是重写父类的某方法;
//源码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
- @Deprecated 标识程序元素已过时、废弃,编译器将不再鼓励使用这个被标注的元素
//源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
- @SuppressWarnings 标识阻止编译器警告,被用于有选择性的关闭编译器对类、方法和成员变量等程序元素及其子元素的警告。此注解会一直作用于该程序的所有子元素;
//源码
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
@SuppressWarnings注解内部有一个String数组,主要接收值:
- deprecation 使用了过时的程序元素
- unchecked 执行了未检查的转换
- unused 有程序元素未被使用
- fallthrough switch程序块直接通往下一种情况而没有break
- path 在类路径、源文件路径等中有不存在的路径
- seial 在可序列化的类上缺少serialVersionUID定义
- finally 任何finally子句不能正常完成
- all 所有情况
package cn.yu.annotation;
/**
* JDK1.5内部提供的三种注解是:@SuppressWarnings(":deprecation")、@Deprecated、@Override
* @author yu
*/
public class AnnotationTest {
@SuppressWarnings("deprecation")
public static void main(String[] args) {
System.runFinalizersOnExit(true);//这里的runFinalizersOnExit()方法画了一条横线表示此方法已经过时了,不建议使用了
}
@Deprecated //这也是JDK内部自带的一个注解,意思就是说这个方法已经废弃了,不建议使用了
public static void sayHello(){
System.out.println("hi,yyyy");
}
@Override //这也是JDK1.5之后内部提供的一个注解,意思就是要重写(覆盖)JDK内部的toString()方法
public String toString(){
return "yyyyy";
}
}
注意:
- 当注解类型中只有一个value成员变量,使用该注解时可以直接在注解后的括号里指定value成员变量的值,而无需使用name=value结构对的形式。例如在@SuppressWarnings注解类型中只有一个value成员变量,则可以把“value=”省略掉:@SuppressWarnings({"unchecked","fallthrough"});
- 若@SuppressWarnings注解所在声明的被禁止的警告个数只有一个时,则可以不用大括号:@SuppressWarnings("unchecked");
2. 元注解
java.lang.annotation包下提供了4个元注解,他们用来修饰其他的注解定义。
- @Target注解
@Target元注解决定了一个注解可以标识到哪些成分上,如标识在在类身上,或者属性身上,或者方法身上等。@Target注解类型由唯一的value作为成员变量。这个成员变量是java.lang.annotation.ElementType类型,ElementType类型是可以被标注的程序元素的枚举类型。@Target的成员变量value为如下值时,则可指定被修饰的注解只能按如下声明进行标注,当value为FIELD时,被修饰的注解只能用来修饰成员变量。
public enum ElementType {
/**标明该注解可以用于类、接口(包括注解类型)或enum声明*/
TYPE,
/** 标明该注解可以用于字段(域)声明,包括enum实例 */
FIELD,
/** 标明该注解可以用于方法声明 */
METHOD,
/** 标明该注解可以用于参数声明 */
PARAMETER,
/** 标明注解可以用于构造函数声明 */
CONSTRUCTOR,
/** 标明注解可以用于局部变量声明 */
LOCAL_VARIABLE,
/** 标明注解可以用于注解声明(应用于另一个注解上)*/
ANNOTATION_TYPE,
/** 标明注解可以用于包声明 */
PACKAGE,
/**
* 标明注解可以用于类型参数声明(1.8新加入)
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 类型使用声明(1.8新加入)
* @since 1.8
*/
TYPE_USE
}
注意,当注解未指定Target值时,则此注解可以用于任何元素之上,多个值使用{}包含并用逗号隔开,如下:
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
- @Rentation注解
@Rentation注解描述了被其修饰的注解是否北边一起丢弃或者保留在class文件中。默认情况下,注解被保存在class文件中,但在运行时不能反射访问。
@Retention用来约束注解的生命周期,分别有三个值,源码级别(source),类文件级别(class)或者运行时级别(runtime),其含有如下:
- SOURCE:注解将被编译器丢弃(该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃,不会保留在编译好的class文件里);
- CLASS:注解在class文件中可用,但会被VM丢弃(该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中),请注意,当注解未定义Retention值时,默认值是CLASS,如Java内置注解,@Override、@Deprecated、@SuppressWarnning等;
- RUNTIME:注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
/*
*通过将value成员变量的值设为RetentionPolicy.RUNTIME,指定@Retention注解在运行时可以通过反射进行访问
*/
@Target(ElementType.ANNOTATION_TYPE )
@Retention(RetentionPolicy.RUNTIME)//保存到运行时
public @interface DBTable {
String name() default "yu";
}
- @Documented注解
用于指定被其修饰的注解将被JavaDoc工具提取成文档,如果再定义某注解时使用了@Documented修饰,则所有使用该注解修饰的程序元素的API文档中都将包含该注解说明。另外,@Documented注解类型没有成员变量。
//定义注解
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DocumentOne { }
//使用注解
@DocumentOne
public class DocumentTest{
public void methodA(){
//....
}
}
- @Inherited注解
用于指定被其修饰的注解将具有继承性,也就是说,如果一个使用了@Inherited注解修饰的注解被用于某个类,则这个注解也将被用于该类的子类(这并不是真的继承,只是通过使用@Inherited,可以让子类Class对象使用getAnnotations()获取父类被@Inherited修饰的注解)。
package cn.SynchronizationDemo;
import java.lang.annotation.*;
import java.util.Arrays; @Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface DocumentOne{ }
@DocumentOne
class ClassA{ }
class ClassB extends ClassA{ }
//测试
public class DocumentTest {
public static void main(String[] args) {
ClassA cla = new ClassB();
System.out.println("使用@Inherited注解:" + Arrays.toString(cla.getClass().getAnnotations())); }
}
3. 自定义注解
注解类型是一种接口,但它有不同于接口。定义一个新的注解类型与定义一个接口非常类似,定义新的注解要使用@interface关键字:
public @interface AnnotationTest{
}
注解定义好后,就可以用来修饰程序中的类、接口、方法和成员变量等。
package cn.AnnotationDemo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* MetaAnnotation注解类为自定义元注解
* @author yu
*/
@interface MetaAnnotation {
String value();//元注解MetaAnnotation设置有一个唯一的属性value
} @Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@interface MyAnnotation {
String color() default "black";
String value();
int[] arrayAttr() default {1,2,4};
//枚举类型
enum EumTrafficLamp {RED,YELLOW,GREEN,BLUE};
EumTrafficLamp lamp() default EumTrafficLamp.RED;
//为注解添加一个注解类型的属性,并指定注解属性的缺省值
MetaAnnotation annotationAttr() default @MetaAnnotation("xjdkf");
}
//这里是将新创建好的注解类MyAnnotation标记到AnnotaionTest类上
@MyAnnotation(color = "red",value = "yu",arrayAttr = {2,4,5},lamp = MyAnnotation.EumTrafficLamp.GREEN,annotationAttr = @MetaAnnotation("sdssss"))
public class AnnotationUse {
public static void main(String[] args) {
// 检查Annotation类是否有注解,这里需要使用反射才能完成对Annotation类的检查
if (AnnotationUse.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation annotation = (MyAnnotation) AnnotationUse.class.getAnnotation(MyAnnotation.class);
System.out.println(annotation.color());
System.out.println(annotation.value());
for (int value:annotation.arrayAttr()) {
System.out.println(value);
}
MyAnnotation.EumTrafficLamp eumTrafficLamp = annotation.lamp();
if(annotation.lamp().equals(eumTrafficLamp.GREEN)) {
System.out.println(annotation.lamp());
}
MetaAnnotation ma = annotation.annotationAttr();//annotation是MyAnnotation类的一个实例对象
System.out.println(ma.value());//输出的结果为:sdssss
}
}
}
4. 读取注解信息
java.lang.reflect包主要包含一些实现反射功能的工具类,另外也提供了对读取运行时注解的支持。java.lang.reflect包下的AnnotationElement接口代表程序中可以接受注解的程序元素,该接口有以下几个实现类:
- Class:类的Class对象定义
- Constructor:代表类的构造器定义
- Field:代表类的成员变量定义
- Method:代表类的方法定义
- Package:代表类的包定义
java.lang.reflect.AnnotatedElement中相关的API方法如下:
package cn.AnnotationDemo;
import java.lang.annotation.Annotation;
import java.lang.annotation.*;
import java.util.Arrays; @Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface DocumentOne {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface DocumentTwo {
} @DocumentOne
class A{ } //继承了A类
@DocumentTwo
public class DocumentDemo extends A{
public static void main(String[] args){
Class<?> clazz = DocumentDemo.class;
//根据指定注解类型获取该注解
DocumentOne documentA=clazz.getAnnotation(DocumentOne.class);
System.out.println("A:"+documentA); //获取该元素上的所有注解,包含从父类继承
Annotation[] an= clazz.getAnnotations();
System.out.println("an:"+ Arrays.toString(an)); //获取该元素上的所有注解,但不包含继承!
Annotation[] an2=clazz.getDeclaredAnnotations();
System.out.println("an2:"+ Arrays.toString(an2)); //判断注解DocumentA是否在该元素上
boolean b=clazz.isAnnotationPresent(DocumentOne.class);
System.out.println("b:"+b);
}
}
注意:
这里得到的注解,都是被定义为运行时的注解,即是用@Retention(RetentionPolicy.RUNTIME)修饰的注解。否则,通过反射得不到这个注解信息。
Java高级特性 第6节 注解初识的更多相关文章
- Java高级特性 第11节 JUnit 3.x和JUnit 4.x测试框架
一.软件测试 1.软件测试的概念及分类 软件测试是使用人工或者自动手段来运行或测试某个系统的过程,其目的在于检验它是否满足规定的需求或弄清预期结果与实际结果之间的差别.它是帮助识别开发完成(中间或最终 ...
- Java高级特性 第5节 序列化和、反射机制
一.序列化 1.序列化概述 在实际开发中,经常需要将对象的信息保存到磁盘中便于检索,但通过前面输入输出流的方法逐一对对象的属性信息进行操作,很繁琐并容易出错,而序列化提供了轻松解决这个问题的快捷方法. ...
- Java高级特性 第14节 解析XML文档(2) - SAX 技术
一.SAX解析XML文档 SAX的全称是Simple APIs for XML,也即XML简单应用程序接口.与DOM不同,SAX提供的访问模式是一种顺序模式,这是一种快速读写XML数据的方式.当使用S ...
- Java高级特性 第8节 网络编程技术
一.网络概述 1.网络的概念和分类 计算机网络是通过传输介质.通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统.网络编程就就是编写程序使联网的两个(或多个)设 ...
- Java高级特性 第2节 java中常用的实用类(1)
一.Java API Java API即Java应用程序编程接口,他是运行库的集合,预先定义了一些接口和类,程序员可以直接调用:此外也特指API的说明文档,也称帮助文档. Java中常用的包: jav ...
- Java高级特性 第1节 集合框架和泛型
Java中,存储多个同类型的数据,可以用数组来实现,但数组有一些缺陷: 数组长度固定不变,布恩那个很好的适应元素数量动态变化的情况 可以通过数组.length获取数组长度,却无法直接获取数组中实际存储 ...
- Java高级特性 第15节 解析XML文档(3) - JDOM和DOM4J技术
一.JDOM解析 特征: 1.仅使用具体类,而不使用接口. 2.API大量使用了Collections类. Jdom由6个包构成: Element类表示XML文档的元素 org.jdom: 解析xml ...
- Java高级特性 第13节 解析XML文档(1) - DOM和XPath技术
一.使用DOM解析XML文档 DOM的全称是Document Object Model,也即文档对象模型.在应用程序中,基于DOM的XML分析器将一个XML文档转换成一个对象模型的集合(通常称DOM树 ...
- Java高级特性 第12节 XML技术
一.XML简介 1. XML介绍 XML是可扩展标记语言(Extensible Markup Language ),XML是一种数据格式,类似 HTML,是使用标签进行内容描述的技术,与HTML不同的 ...
随机推荐
- ionic UI Component Slides使用:手动滑动后自动滑动失效解决
在使用ionic的UI组件Slides时,发现手动滑动后,自动滑动失效 然后历经一点点的艰辛查找后找到方法,如下: 页面代码使用 <ion-slides pager loop="tru ...
- android Studio 出现:Unable to resolve dependency for ':app@debug/compileClasspath'
li经千辛万苦,我的新工程gradle搞定了 但是却在变异的时候告诉我 Unable to resolve dependency for ':app@debug/compileClasspath'xx ...
- Struts2中 Action class not found 问题
刚学Struts2时碰到了以下两个问题,都是没有正确配置struts.xml导致的,自己记录一下: 1.浏览器报404:The origin server did not find a current ...
- ndarray对象的使用方法
ndarray的基本操作 1.索引 基本索引:一维与list完全一致 多维同理 例如: import numpy ndarr1 = numpy.random.randint(0,10.size=5) ...
- Javascript时间戳和日期时间的相互转换
跟后台对接的时候经常碰到时间格式的问题,有时返回的是时间戳,有时返回的是具体时间,需求又需要它们之间的转换,所以干脆把之前遇到过的情况都给记录下来,以供自己参考! 本文备注:(时间戳单位为毫秒ms,换 ...
- (01) 什么是Spring Boot
1.Spring Boot 是spring家族的全新框架: Spring Boot 是简化spring 应用程序的创建和开发过程, 也就是说Spring Boot 能够简化之前采用ssh, ssm框架 ...
- fiddler抓取用tomcat来部署的项目接口请求包
Fiddler 是以代理web服务器的形式工作的,它使用代理地址:127.0.0.1,端口:8888. 当Fiddler退出的时候它会自动注销, 这样就不会影响别的程序.关于fiddler这个工具的使 ...
- Cookie中的sessionid与JSONP原理
一.首先说明一下cookie中的sessionid的作用. 1.cookie只是一些文本内容,多是键值对的形式,是请求头中的一部分 2.http是无连接的 知道这两点,就可以很容易的理解session ...
- Spring mvc初学
转自:http://www.cnblogs.com/bigdataZJ/p/springmvc1.html 从今天起,准备好好审视并学习Spring mvc. 虽然从学java的第一个程序——hell ...
- find补充和目录结构
第1章 find找出文件然后通过ls -l显示文件的详细信息 找出/oldboy 以.sh结尾的文件,显示文件详细信息 1.1 方法一: find /oldboy/ -type f -name &qu ...