Java核心 --- 注解
Java核心——注解
注解是jdk5以后的新特性,Spring和Hibernate等框架提供了注解的配置方式使用,
本文参考了浪曦风中叶的注解讲解,主要讲解jdk内置注解的用法,注解的声明和定义,以及自定义注解的用法
写过java代码的很多程序员都是用过注解,但是也只是知道一些皮毛
比如:注释是给人看的,注解是给编译器看的;前面加一个@就可以了
一般常用的也就是@Override,@SuppressWarnings之类的注解
下面,我们会给出详细说明:
一、JDK5后的新特性,Annotation
在java应用中,我们常遇到一些使用模板代码的情况
例如,为了编写一个web service,
我们必须提供一对接口和实现作为模板代码
如果使用annotation对远程访问的方法进行修饰的话
这个模板就能够使用工具自动生成
另外,一些API需要使用与程序代码同时维护附属文件
例如,EJB需要一个部署描述符。此时在程序中
使用annotation来维护这些附属文件的信息,将十分便利而且减少了错误
jdk内置的注解,Override,Deprecated,SuppressWarnings
@Override,强制去检查子类的方法覆盖了父类的方法
/Annotation/src/yuki/corejava/annotation/jdk5/OverrideTest.java
下面的类重写了父类Object中的toString()方法
package yuki.corejava.annotation.jdk5;
public class OverrideTest {
@Override
public String toString() {
return "This is override";
}
public static void main(String[] args) {
OverrideTest test = new OverrideTest();
System.out.println(test.toString());
}
}
从Java5.0版发布以来,5.0平台提供了一个正式的annotation功能
允许开发者定义,使用自己的annotation类型
此功能由一个定义annotation类型的语法和一个描述annotation声明的语法
读取annotation的API,
一个使用annotation修饰的class文件,一个annotation处理工具(apt)组成
annotation并不直接影响代码的语义,
但是它能够工作的方式被看作类似程序的工具或者类库
它会反过来对正在运行的程序语义有所影响
annotation可以从源文件、class文件或者以正在运行时的反射的多种方式被读取
当然,annotation在某种程度上使javadoc tag更加完整
一般情况下,如果这个标记对java文档产生影响或者用于生成java文档的话
它应该作为一个javadoc tag,否则将作为一个annotation
限定Override父类方法 @Override
java.lang.Override是一个marker annotation
它的作用是让编译器检查下面的方法一定是重写方法,否则编译会报错
对编译器说明某个方法已经不建议使用 @Deprecated
java.lang.Deprecated是一个marker annotation
/Annotation/src/yuki/corejava/annotation/jdk5/DeprecatedTest.java
package yuki.corejava.annotation.jdk5;
public class DeprecatedTest {
@Deprecated
public void doSomeThing() {
System.out.println("do some thing");
}
public static void main(String[] args) {
DeprecatedTest test = new DeprecatedTest();
test.doSomeThing();
}
}
当子类继承父类后,重写父类的过时方法,开发环境会报出警告
/Annotation/src/yuki/corejava/annotation/jdk5/SubDeprecatedTest.java
package yuki.corejava.annotation.jdk5;
public class SubDeprecatedTest extends DeprecatedTest {
@SuppressWarnings("deprecation")
@Override
public void doSomeThing() {
System.out.println("do some thing in sub class");
}
}
如果没有报出警告,可以在勾选下面的复选框

压制编译程序警告 @SuppressWarnings
对编译程序说明某个方法中若有警告讯息,则加以抑制
/Annotation/src/yuki/corejava/annotation/jdk5/SuppressWarningsTest.java
package yuki.corejava.annotation.jdk5;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
public class SuppressWarningsTest {
@SuppressWarnings({ "unchecked", "rawtypes", "deprecation" })
public static void main(String[] args) {
Map map = new TreeMap();
map.put("hello", new Date());
System.out.println(map.get("hello"));
DeprecatedTest test = new DeprecatedTest();
test.doSomeThing();
}
}
二、自定义Annotation
@interface可以定义Annotation类型
定义好的Annotation可以放在方法前或类前或属性上
定义一个带属性的Annotation,定义一个属性value
如果属性名不是value,在使用时必须显式定义
字符串可以看做字符串数组中的一个特例,所以可以复制给数组
这里就像接口定义一样,只有声明没有实现
给字符串一个默认值
/Annotation/src/yuki/corejava/annotation/define/p1/AnnotationTest.java
package yuki.corejava.annotation.define.p1;
public @interface AnnotationTest {
// String value1();
// String value();
// String[] value();
String value() default "default string";
}
/Annotation/src/yuki/corejava/annotation/define/p1/AnnotationUsage.java
package yuki.corejava.annotation.define.p1;
public class AnnotationUsage {
// @AnnotationTest(value1 = "hello world")
// @AnnotationTest("hello world")
@AnnotationTest
public void method(){
System.out.println("usage of annotation");
}
public static void main(String[] args) {
AnnotationUsage usage = new AnnotationUsage();
usage.method();
}
}
可以使用枚举来定义一些固定的备选值,枚举可以定义在方法中
这里,为了简便起见,定义了一个公开的枚举
/Annotation/src/yuki/corejava/annotation/define/p2/EnumTest.java
package yuki.corejava.annotation.define.p2;
public enum EnumTest {
Hello, World, Welcome
}
/Annotation/src/yuki/corejava/annotation/define/p2/AnnotationTest.java
package yuki.corejava.annotation.define.p2;
public @interface AnnotationTest {
EnumTest value1() default EnumTest.Hello;
}
/Annotation/src/yuki/corejava/annotation/define/p2/AnnotationUsage.java
package yuki.corejava.annotation.define.p2;
public class AnnotationUsage {
// @AnnotationTest(value1 = EnumTest.Hello)
@AnnotationTest
public void method(){
System.out.println("usage of annotation");
}
public static void main(String[] args) {
AnnotationUsage usage = new AnnotationUsage();
usage.method();
System.out.println(EnumTest.Hello);
}
}
主函数的运行结果输出在控制台上的内容如下:
usage of annotation Hello
使用 @interface自定义Annotation型态时,
实际上是自动隐式继承了java.lang.annotation.Annotation接口
由编译程序自动完成其它产生的细节
如果显式的继承了Annotation接口得接口,它只是一个普通的接口
注解类型的声明不能有显式的继承父接口
告知编译程序如何处理 @Retention
java.lang.annotation.Retention型态可以在定义Annotation型态时
指示编译程序该如何对待您的自定义的Annotation型态
预设编译程序将Annotation信息留在.class档案中
但不被虚拟机读取,而仅用于编译程序或工具程序运行时提供信息
在使用Retention型态时,
需要提供java.lang,annotation.RetentionPolicy的枚举型态
public enum RetentionPolicy{
SOURCE, //编译程序处理完Annotation就完成任务
CLASS, //编译程序将Annotation储存在class当中,缺省
RUNTIME //编译程序将Annotation储存于class当中,可由VM读入
}
/Annotation/src/yuki/corejava/annotation/define/MyAnnotation.java
package yuki.corejava.annotation.define;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String hello() default "default hello";
String world();
}
RetentionPolicy为SOURCE的例子是 @SuppressWarnings
仅在编译时告知编译程序来抑制警告,所以不必将这个信息储存在.class档案
RetentionPolicy为RUNTIME的时机,
可以像是使用Java设计一个程序代码分析工具
必须让VM读出Annotation信息,以便在流程分析程序时使用
搭配反射机制,就可以达到这个目的
运行时把Annotation的信息读取出来
通过反射的方式获得注解的属性
这些在Hibernate和Spring中都有使用,通过注解就可以轻松配置
获得方法前的所有注解遍历
/Annotation/src/yuki/corejava/annotation/define/MyReflection.java
package yuki.corejava.annotation.define;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class MyReflection {
public static void main(String[] args) throws Exception {
MyTest myTest = new MyTest();
Class<MyTest> c = MyTest.class;
Method method = c.getMethod("output", new Class[]{});
if(method.isAnnotationPresent(MyAnnotation.class)){
method.invoke(myTest, new Object[]{});
MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
String hello = myAnnotation.hello();
String world = myAnnotation.world();
System.out.println(hello);
System.out.println(world);
}
Annotation[] annotations = method.getAnnotations();
for(Annotation annotation : annotations){
System.out.println(annotation.annotationType().getName());
}
}
}
/Annotation/src/yuki/corejava/annotation/define/MyTest.java
package yuki.corejava.annotation.define;
public class MyTest {
@MyAnnotation(hello = "beijing" ,world = "shanghai")
@Deprecated
// @SuppressWarnings("unchecked")
public void output(){
System.out.println("output something");
}
}
运行结果如下,拿到了注解中属性的右值——"beijing","shanghai"
遍历除了这个方法上所有的RUNTIME的注解
output something beijing shanghai yuki.corejava.annotation.define.MyAnnotation java.lang.Deprecated
告知编译程序如何处理 @Retention
java.lang.reflect.AnnotatedElement接口
定义Annotation时必须设定RetentionPolicy为RUNTIME
就可以在VM中读取Annotation信息
因为 @SuppressWarnings 有 @Retention(RetentionPolicy.SOURCE)
所以在编译后,没有存在
当Retention的值为RetentionPolicy.CLASS时
注解的信息只会在.class文件中存在,而并不会被读出
/Annotation/src/yuki/corejava/annotation/define/p4/EnumTest.java
package yuki.corejava.annotation.define.p4;
public enum EnumTest {
HELLO, WORLD, welcome
}
/Annotation/src/yuki/corejava/annotation/define/p4/AnnotationTest.java
package yuki.corejava.annotation.define.p4;
public @interface AnnotationTest {
EnumTest value1() default EnumTest.HELLO;
String value2();
Class<?> c();
// Date date();
}
当声明Date时,编译器提示出如下结果:
Invalid type Date for the annotation attribute AnnotationTest.date; only primitive type, String, Class, annotation, enumeration are permitted or 1-dimensional arrays thereof
Invalid type Date for the annotation attribute AnnotationTest.date;
only primitive type, String, Class, annotation, enumeration
are permitted or 1-dimensional arrays thereof
就是说,只能定义基本类型,字符串,类,注解,枚举,以及他们的一维数组
三、Target, Documented, Inherited
限定annotation适用对象的 @Target
使用java.lang.annotation.Target可以定义其使用的时机
如果不加目标,注解就可以定义在任何地方
在定义时要指定java.lang.annotation.ElementType的枚举值之一
public enum ElementType{
TYPE, //class, interface, enum
METHOD, //method
PARAMETER, //parameter of method
CONSTRUCTOR, //constructor
LOCAL_VARIABLE, //local varible
ANNOTATION_TYPE,//annotation
PACKAGE //package
}
如果注解的位置没有放对的话,就会给出如下警告
The annotation @MyTarget is disallowed for this location
/Annotation/src/yuki/corejava/annotation/define/target/MyTarget.java
package yuki.corejava.annotation.define.target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface MyTarget {
String value();
}
/Annotation/src/yuki/corejava/annotation/define/target/MyTargetTest.java
package yuki.corejava.annotation.define.target;
//@MyTarget("value")
public class MyTargetTest {
@MyTarget("value")
public void doSomeThing(){
System.out.println("do some thing");
}
}
要求为API文件 @Documented
想要在使用者制作JavaDoc文件的同时
也一并将Annotation的讯息加入至API中
使用java.lang.annotation.Documented
/Annotation/src/yuki/corejava/annotation/define/doc/DocumentAnnotation.java
package yuki.corejava.annotation.define.doc;
import java.lang.annotation.Documented;
@Documented
public @interface DocumentAnnotation {
String hello();
}
/Annotation/src/yuki/corejava/annotation/define/doc/DocumentTest.java
package yuki.corejava.annotation.define.doc;
public class DocumentTest {
/**
* This is comments that I have added
*/
@DocumentAnnotation(hello = "welcome")
public void method(){
System.out.println("hello world");
}
}

点击生成javadoc,生成的文件如下:

子类是否继承父类 @Inherited 。。。?
预设父类别中的Annotation并不会被继承至子类别中
可以在定义Annotation型态时加上
java.lang.annotation.Inherited型态的Annotation
类的注解和方法的注解都可以继承到子类
/Annotation/src/yuki/corejava/annotation/define/doc/InheritedTest.java
package yuki.corejava.annotation.define.doc;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedTest {
String value();
}
/Annotation/src/yuki/corejava/annotation/define/doc/Parent.java
package yuki.corejava.annotation.define.doc;
@InheritedTest("welcome")
public class Parent {
public void doSomeThing(){
System.out.println("hello");
}
}
/Annotation/src/yuki/corejava/annotation/define/doc/Child.java
package yuki.corejava.annotation.define.doc;
public class Child extends Parent {
}
/Annotation/src/yuki/corejava/annotation/define/doc/Test.java
package yuki.corejava.annotation.define.doc;
public class Test {
public static void main(String[] args) {
Class<Child> c = Child.class;
// Class<Parent> c = Parent.class;
if(c.isAnnotationPresent(InheritedTest.class)){
InheritedTest inheritedTest = c.getAnnotation(InheritedTest.class);
String value = inheritedTest.value();
System.out.println(value);
}
}
}
运行结果如下:
welcome
如果子类重写父类的方法,父类方法中的注解也会被覆盖掉
/Annotation/src/yuki/corejava/annotation/define/inherit/InheritedTest.java
package yuki.corejava.annotation.define.inherit;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedTest {
String value();
}
/Annotation/src/yuki/corejava/annotation/define/inherit/Parent.java
package yuki.corejava.annotation.define.inherit;
public class Parent {
@InheritedTest("welcome")
public void doSomeThing(){
System.out.println("parent do some thing");
}
}
/Annotation/src/yuki/corejava/annotation/define/inherit/Child.java
package yuki.corejava.annotation.define.inherit;
public class Child extends Parent {
@Override
public void doSomeThing(){
System.out.println("child do some thing");
}
}
/Annotation/src/yuki/corejava/annotation/define/inherit/Test.java
package yuki.corejava.annotation.define.inherit;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
Class<Child> c = Child.class;
Method method = c.getMethod("doSomeThing", new Class[]{});
if(method.isAnnotationPresent(InheritedTest.class)){
InheritedTest inheritedTest = method.getAnnotation(InheritedTest.class);
String value = inheritedTest.value();
System.out.println(value);
}
}
}
运行时在控制台上没有输出。即父类的注解也被覆盖了
只会在继承父类时继承,而不会在实现接口时继承
/Annotation/src/yuki/corejava/annotation/define/inherit/ParentInterface.java
package yuki.corejava.annotation.define.inherit;
@InheritedTest("welcome")
public interface ParentInterface {
}
/Annotation/src/yuki/corejava/annotation/define/inherit/ChildClass.java
package yuki.corejava.annotation.define.inherit;
public class ChildClass implements ParentInterface {
}
/Annotation/src/yuki/corejava/annotation/define/inherit/TestInterface.java
package yuki.corejava.annotation.define.inherit;
public class TestInterface {
public static void main(String[] args) throws Exception {
Class<ChildClass> c = ChildClass.class;
if(c.isAnnotationPresent(InheritedTest.class)){
InheritedTest inheritedTest = c.getAnnotation(InheritedTest.class);
String value = inheritedTest.value();
System.out.println(value);
}
}
}
运行结果也是没有任何结果,说明接口的注解不能被实现类继承。
更多精彩文章请查看:http://www.cnblogs.com/kodoyang/
孔东阳
2014/8/13
Java核心 --- 注解的更多相关文章
- java 利用注解实现BaseDao 增删查改
第一步,编写两个注解类,用于表明实体类对应的表名及字段. TableInfo.java 此注解用于标注表名及主键名 import static java.lang.annotation.Element ...
- Java核心编程快速学习
Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...
- SpringBoot核心注解应用
1.今日大纲 了解Spring的发展 掌握Spring的java配置方式 学习Spring Boot 使用Spring Boot来改造购物车系统 2.Spring的发展 Spring1.x 时代 在S ...
- Java核心编程快速入门
Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体内容如下图所示. 反射reflect是理解Java语言工作原理的基础,Java编译器首先需要将我们编写的 ...
- Java核心编程快速学习(转载)
http://www.cnblogs.com/wanliwang01/p/java_core.html Java核心编程部分的基础学习内容就不一一介绍了,本文的重点是JAVA中相对复杂的一些概念,主体 ...
- SpringBoot的核心注解和配置
一.入口类和SpringBootApplication Spring Boot的项目一般都会有*Application的入口类,入口类中会有main方法,这是一个标准的Java应用程序的入口方法. @ ...
- 自己写的基于java Annotation(注解)的数据校验框架
JavaEE6中提供了基于java Annotation(注解)的Bean校验框架,Hibernate也有类似的基于Annotation的数据校验功能,我在工作中,产品也经常需要使 用数据校验,为了方 ...
- 使用Java元注解和反射实现简单MVC框架
Springmvc的核心是DispatcherServlet来进行各种请求的拦截,进而进行后续的各种转发处理.流程图如下: 说明:客户端发出一个http请求给web服务器,web服务器对http请求进 ...
- Spring Boot 运行原理 - 核心注解
https://www.jianshu.com/p/23f504713b94 核心注解 打开上面任意一个AutoConfiguration文件,一般都有下面的条件注解,在spring-boot-aut ...
随机推荐
- centos磁盘爆满,查找大文件并清理
今天发现vps敲入crontab -e 居然提示 “Disk quota exceeded” 无法编辑.于是"df -h"查了查发现系统磁盘空间使用100%了.最后定位到是/var ...
- oracle11g OEM无法连接到数据库实例解决办法
我的电脑是32位的win7家庭版系统,那么这样的系统能不能装上oracle呢?能的!就是可能会出错,在装oracle时,每个人遇到的问题都不同,有的人装了双系统,有的人重做了系统,真心酸,先让电脑断网 ...
- Sails 自定义 model 方法
Sails 自定义 model 方法 在 Sails 中 model 提供了一些原生的静态方法,如 .create(), .update(), .destroy(), .find(), 等. 在实际业 ...
- Java I/O操作学习笔记
书上写的有点乱,所以就自己总结了一下,主要参考:http://www.cnblogs.com/qianbi/p/3378466.html 1.从文件读出和写入: import java.io.*; i ...
- ccnu-线段树-简单的区间更新(三题)
题目一:http://poj.org/problem?id=3468 Description You have N integers, A1, A2, ... , AN. You need to de ...
- python 捕获 shell/bash 脚本的输出结果
#!/usr/bin/python## get subprocess module import subprocess ## call date command ##p = subprocess.Po ...
- C++ STL之priority_queue
STL中的priority_queue(优先队列)是一种会按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序的容器,不同优先级的情况下,top()上永远是最高优先级的数据,其底层采用的 ...
- HTML+CSS+JAVASCRIPT 总结
1. HTML 1: <!doctype html> 2: <!-- This is a test html for html, css, javascript --> 3: ...
- Java面向对象编程概述
一. 01.软件开发经历周期: 软件分析:分析问题领域,了解客户的需求 软件设计:确定软件的总体结构,把整个软件系统划分为大大小小的多个子系统,设计每个子系统的具体结构 软件编码:用选定的编程语言来编 ...
- Uva 10382 (区间覆盖) Watering Grass
和 Uva 10020几乎是一样的,不过这里要把圆形区域转化为能够覆盖的长条形区域(一个小小的勾股定理) 学习一下别人的代码,练习使用STL的vector容器 这里有个小技巧,用一个微小量EPS来弥补 ...