java注解

一、认识注解

注解(Annotation)很重要,未来的开发模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,现在的Struts2有一部分也是基于注解的了,注解是一种趋势,现在已经有不少的人开始用注解了,注解是JDK1.5之后才有的新特性

JDK1.5之后内部提供的三个注解

@Deprecated 意思是“废弃的,过时的

@Override 意思是“重写、覆盖

@SuppressWarnings 意思是“压缩警告

范例:注解的应用:

package cn.gacl.annotation;
/**
 * 此类是用来演示注解(Annotation)的应用的,注解也是JDK1.5新增加的特性之一
 * JDK1.5内部提供的三种注解是:@SuppressWarnings(":deprecation")、@Deprecated、@Override
 * @author 孤傲苍狼
 *
 */
/**
 * 类名的命名是有讲究的,类名、属性名、变量名一般是名词,或者是形容词+名词,方法一般是动词,或者是动词+名词,
 * 以AnnotationTest作为类名和以TestAnnotation作为类名是有区别的,
 * 前者是注解的测试,符合名词的特征,后者是测试注解,听起来就是一个动作名称,是方法的命名特征
 */
public class AnnotationTest {
    /**
     * @param args
     */
    @SuppressWarnings(":deprecation")
    //这里就是注解,称为压缩警告,这是JDK内部自带的一个注解,一个注解就是一个类,在这里使用了这个注解就是创建了SuppressWarnings类的一个实例对象
    public static void main(String[] args) {
        System.runFinalizersOnExit(true);
        //The method runFinalizersOnExit(boolean) from the type System is deprecated(过时的,废弃的)
        //这里的runFinalizersOnExit()方法画了一条横线表示此方法已经过时了,不建议使用了
    }
    @Deprecated //这也是JDK内部自带的一个注解,意思就是说这个方法已经废弃了,不建议使用了
    public static void sayHello(){
        System.out.println("hi,孤傲苍狼");
    }
    @Override //这也是JDK1.5之后内部提供的一个注解,意思就是要重写(覆盖)JDK内部的toString()方法
    public String toString(){
        return "孤傲苍狼";
    }
}

总结:注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,没有加,则等于没有任何标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无何种标记,看你的程序有什么标记,就去干相应的事,标记可以加在包、类,属性、方法,方法的参数以及局部变量上。

**<figure style="margin: 1em 0px;">
image

</figure>**

注解就相当于一个你的源程序要调用一个类,在源程序中应用某个注解,得事先准备好这个注解类。就像你要调用某个类,得事先开发好这个类。

二、自定义注解及其应用

自定义一个最简单的注解:

1 public @interface MyAnnotation{}

package cn.gacl.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 这是一个自定义的注解(Annotation)类 在定义注解(Annotation)类时使用了另一个注解类Retention
 * 在注解类上使用另一个注解类,那么被使用的注解类就称为元注解
 * 
 * @author 孤傲苍狼
 * 
 */
@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target( { ElementType.METHOD, ElementType.TYPE })
//Target注解决定MyAnnotation注解可以加在哪些成分上,如加在类身上,或者属性身上,或者方法身上等成分
/*
 * @Retention(RetentionPolicy.SOURCE)
 * 这个注解的意思是让MyAnnotation注解只在java源文件中存在,编译成.class文件后注解就不存在了
 * @Retention(RetentionPolicy.CLASS)
 * 这个注解的意思是让MyAnnotation注解在java源文件(.java文件)中存在,编译成.class文件后注解也还存在,
 * 被MyAnnotation注解类标识的类被类加载器加载到内存中后MyAnnotation注解就不存在了
 */
/*
 * 这里是在注解类MyAnnotation上使用另一个注解类,这里的Retention称为元注解。
 * Retention注解括号中的"RetentionPolicy.RUNTIME"意思是让MyAnnotation这个注解的生命周期一直程序运行时都存在
 */
public @interface MyAnnotation {
}

把自定义的注解加到某个类上:

1 @ MyAnnotation 
2 public class AnnotationUse{
3 
4 }

用反射测试进行测试AnnotationUse的定义上是否有@MyAnnotation

package cn.gacl.annotation;
@MyAnnotation
//这里是将新创建好的注解类MyAnnotation标记到AnnotaionTest类上
public class AnnotationUse {
    public static void main(String[] args) {
        // 这里是检查Annotation类是否有注解,这里需要使用反射才能完成对Annotation类的检查
        if (AnnotationUse.class.isAnnotationPresent(MyAnnotation.class)) {
            /*
             * MyAnnotation是一个类,这个类的实例对象annotation是通过反射得到的,这个实例对象是如何创建的呢?
             * 一旦在某个类上使用了@MyAnnotation,那么这个MyAnnotation类的实例对象annotation就会被创建出来了
             * 假设很多人考驾照,教练在有些学员身上贴一些绿牌子、黄牌子,贴绿牌子的表示送礼送得比较多的,
             * 贴黄牌子的学员表示送礼送得比较少的,不贴牌子的学员表示没有送过礼的,通过这个牌子就可以标识出不同的学员
             * 教官在考核时一看,哦,这个学员是有牌子的,是送过礼给他的,优先让有牌子的学员过,此时这个牌子就是一个注解
             * 一个牌子就是一个注解的实例对象,实实在在存在的牌子就是一个实实在在的注解对象,把牌子拿下来(去掉注解)注解对象就不存在了
             */
            MyAnnotation annotation = (MyAnnotation) AnnotationUse.class
                    .getAnnotation(MyAnnotation.class);
            System.out.println(annotation);// 打印MyAnnotation对象,这里输出的结果为:@cn.itcast.day2.MyAnnotation()
        }
    }
}

三、@Retention元注解

根据反射的测试的问题,引出@Retention元注解的讲解:其三种取值:RetentionPolicy.SOURCERetentionPolicy.CLASSRetentionPolicy.RUNTIME分别对应:Java源文件(.java文件)---->.class文件---->内存中的字节码

四、 Retention注解说明

当在Java源程序上加了一个注解,这个Java源程序要由javac去编译,javac把java源文件编译成.class文件,在编译成class时可能会把Java源程序上的一些注解给去掉,java编译器(javac)在处理java源程序时,可能会认为这个注解没有用了,于是就把这个注解去掉了,那么此时在编译好的class中就找不到注解了, 这是编译器编译java源程序时对注解进行处理的第一种可能情况,假设java编译器在把java源程序编译成class时,没有把java源程序中的注解去掉,那么此时在编译好的class中就可以找到注解,当程序使用编译好的class文件时,需要用类加载器把class文件加载到内存中,class文件中的东西不是字节码,class文件里面的东西由类加载器加载到内存中去,类加载器在加载class文件时,会对class文件里面的东西进行处理,如安全检查,处理完以后得到的最终在内存中的二进制的东西才是字节码,类加载器在把class文件加载到内存中时也有转换,转换时是否把class文件中的注解保留下来,这也有说法,所以说一个注解的生命周期有三个阶段:java源文件是一个阶段,class文件是一个阶段,内存中的字节码是一个阶段,javac把java源文件编译成.class文件时,有可能去掉里面的注解,类加载器把.class文件加载到内存时也有可能去掉里面的注解,因此在自定义注解时就可以使用Retention注解指明自定义注解的生命周期,自定义注解的生命周期是在RetentionPolicy.SOURCE阶段(java源文件阶段),还是在RetentionPolicy.CLASS阶段(class文件阶段),或者是在RetentionPolicy.RUNTIME阶段(内存中的字节码运行时阶段),根据JDK提供的API可以知道默认是在RetentionPolicy.CLASS阶段 (JDK的API写到:the retention policy defaults to RetentionPolicy.CLASS.)

下面看看@Deprecated、@Override、@SuppressWarnings这三个注解的@Retention注解的属性值分别是什么吧

4.1、@Deprecated

Java API中是这样定义的@Deprecated的

1 @Documented
2 @Retention(value=RUNTIME)
3 public @interface Deprecated

4.2、@Override

Java API中是这样定义的@Override的

1 @Target(value=METHOD)
2 @Retention(value=SOURCE)
3 public @interface Override

@Override是给javac(java编译器)看的,编译完以后就@Override注解就没有价值了,@Override注解在源代码中有用,编译成.class文件后@Override注解就没有用了,因此@Override的Retention的属性值是RetentionPolicy.SOURCE

4.3、@SuppressWarnings

Java API中是这样定义的@SuppressWarnings的

1 @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
2 @Retention(value=SOURCE)
3 public @interface SuppressWarnings

@SuppressWarnings是给javac(java编译器)看的,编译器编译完java文件后,@SuppressWarnings注解就没有用了,所以@SuppressWarnings的Retention的属性值是RetentionPolicy.SOURCE

五、@Target元注解

@Target元注解决定了一个注解可以标识到哪些成分上,如标识在在类身上,或者属性身上,或者方法身上等成分,@Target默认值为任何元素(成分)

例如:

1 @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE})
2 @Retention(value=SOURCE)
3 public @interface SuppressWarnings

六、为注解增加属性

注解可以看成是一种特殊的类,既然是类,那自然可以为类添加属性

6.1.添加属性

 语法:类型 属性名();

package cn.gacl.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
    /**
     * 定义基本属性
     * @return
     */
    String color();
}

其实从代码的写法上来看,注解更像是一种特殊的接口,注解的属性定义方式就和接口中定义方法的方式一样,而应用了注解的类可以认为是实现了这个特殊的接口

6.2.应用属性

package cn.gacl.annotation;

@MyAnnotation(color="red")//应用MyAnnotation注解的color属性
public class MyAnnotationTest {
    public static void main(String[] args) {
        /**
         * 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
         */
        MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.color());//输出red
    }
}

6.3.为属性指定缺省值(默认值)

  语法:类型 属性名() default 默认值;

package cn.gacl.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
    String color() default "blue";//为属性指定缺省值
}

package cn.gacl.annotation;

@MyAnnotation
public class MyAnnotationTest {
    public static void main(String[] args) {
        /**
         * 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
         */
        MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.color());//输出color属性的默认值:blue

    }
}

6.4.value属性

如果一个注解中有一个名称为value的属性,且你只想设置value属性(即其他属性都采用默认值或者你只有一个value属性),那么可以省略掉“value=”部分。

例如:@SuppressWarnings("deprecation")

package cn.gacl.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target( { ElementType.METHOD, ElementType.TYPE })
public @interface MyAnnotation {
    String color() default "blue";//为属性指定缺省值
    String value();//定义一个名称为value的属性
}

package cn.gacl.annotation;

@MyAnnotation("孤傲苍狼")//等价于@MyAnnotation(value="孤傲苍狼")
public class MyAnnotationTest {
    public static void main(String[] args) {
        /**
         * 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
         */
        MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
        System.out.println(annotation.color());//输出color属性的默认值:blue
        System.out.println(annotation.value());

    }
}

七、为注解增加高级属性

7.1、数组类型的属性

  • 增加数组类型的属性:int[] arrayAttr() default {1,2,4};
  • 应用数组类型的属性:@MyAnnotation(arrayAttr={2,4,5})
  • 如果数组属性只有一个值,这时候属性值部分可以省略大括号,如:@MyAnnotation(arrayAttr=2),这就表示数组属性只有一个值,值为2

7.2.、枚举类型的属性

  • 增加枚举类型的属性:EumTrafficLamp lamp() default EumTrafficLamp.RED;
  • 应用枚举类型的属性:@MyAnnotation(lamp=EumTrafficLamp.GREEN)

7.3、注解类型的属性

/**
 * MetaAnnotation注解类为元注解
 * @author 孤傲苍狼
 *
 */
public @interface MetaAnnotation {
    String value();//元注解MetaAnnotation设置有一个唯一的属性value
}

为注解添加一个注解类型的属性,并指定注解属性的缺省值:MetaAnnotation annotationAttr() default @MetaAnnotation("xdp");

八、注解综合测试

EumTrafficLamp.java

package cn.gacl.annotation;
/**
 * 交通信号灯颜色枚举
 * @author 孤傲苍狼
 *
 */
public enum EumTrafficLamp {
    RED,//红
    YELLOW,//黄
    GREEN//绿
}

MetaAnnotation.java

/**
 * MetaAnnotation注解类为元注解
 * @author 孤傲苍狼
 *
 */
public @interface MetaAnnotation {
    String value();//元注解MetaAnnotation设置有一个唯一的属性value
}

MyAnnotation.java

package cn.gacl.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
//Retention注解决定MyAnnotation注解的生命周期
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface MyAnnotation {
    String color() default "blue";//为属性指定缺省值
    /**
     * 为注解添加value属性,这个value属性很特殊,如果一个注解中只有一个value属性要设置,
     * 那么在设置注解的属性值时,可以省略属性名和等号不写, 直接写属性值,如@SuppressWarnings("deprecation"),
     * 这里的MyAnnotation注解设置了两个String类型的属性,color和value,
     * 因为color属性指定有缺省值,value属性又是属于特殊的属性,因此使用MyAnnotation注解时
     * 可以这样使用MyAnnotation注解:"@MyAnnotation(color="red",value="xdp")"
     * 也可以这样使用:"@MyAnnotation("孤傲苍狼")",这样写就表示MyAnnotation注解只有一个value属性要设置,color属性采用缺省值
     * 当一个注解只有一个value属性要设置时,是可以省略"value="的
     */
    String value();//定义一个名称为value的属性
    //添加一个int类型数组的属性
    int[] arrayAttr() default {1,2,4};
    //添加一个枚举类型的属性,并指定枚举属性的缺省值,缺省值只能从枚举类EumTrafficLamp中定义的枚举对象中取出任意一个作为缺省值
    EumTrafficLamp lamp() default EumTrafficLamp.RED;
    //为注解添加一个注解类型的属性,并指定注解属性的缺省值
    MetaAnnotation annotationAttr() default @MetaAnnotation("xdp");

}

MyAnnotationTest.java

package cn.gacl.annotation;
/**
 * 这里是将新创建好的注解类MyAnnotation标记到AnnotaionTest类上,
 * 并应用了注解类MyAnnotation中定义各种不同类型的的属性
 */
@MyAnnotation(
        color="red",
        value="孤傲苍狼",
        arrayAttr={3,5,6},
        lamp=EumTrafficLamp.GREEN,
        annotationAttr=@MetaAnnotation("gacl")
        )
public class MyAnnotationTest {
    @MyAnnotation("将MyAnnotation注解标注到main方法上")
    public static void main(String[] args) {
        /**
         * 这里是检查Annotation类是否有注解,这里需要使用反射才能完成对Annotation类的检查
         */
        if(MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
            /**
             * 用反射方式获得注解对应的实例对象后,在通过该对象调用属性对应的方法
             * MyAnnotation是一个类,这个类的实例对象annotation是通过反射得到的,这个实例对象是如何创建的呢?
             * 一旦在某个类上使用了@MyAnnotation,那么这个MyAnnotation类的实例对象annotation就会被创建出来了
             */
            MyAnnotation annotation = (MyAnnotation) MyAnnotationTest.class.getAnnotation(MyAnnotation.class);
            System.out.println(annotation.color());//输出color属性的默认值:red
            System.out.println(annotation.value());//输出value属性的默认值:孤傲苍狼
            System.out.println(annotation.arrayAttr().length);//这里输出的数组属性的长度的结果为:3,数组属性有三个元素,因此数组的长度为3
            System.out.println(annotation.lamp());//这里输出的枚举属性值为:GREEN
            System.out.println(annotation.annotationAttr().value());//这里输出的注解属性值:gacl

            MetaAnnotation ma = annotation.annotationAttr();//annotation是MyAnnotation类的一个实例对象
            System.out.println(ma.value());//输出的结果为:gacl

        }
    }
}

本来想自己写一篇关于注解的文章,但是发现网上有很好的讲解注解的博客,就转载了过来。

本文转载自:Java基础加强总结(一)--注解(Annotation) - 孤傲苍狼 - 博客园

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配...
    尼尔君阅读 515评论 0 0
  • 以前,『XML』是各大框架的青睐者,它以松耦合的方式完成了框架中几乎所有的配置,但是随着项目越来越庞大,『XML』...
    Java大生阅读 2,375评论 3 96
  • 一、什么是注解? 注解对于开发人员来讲既熟悉又陌生,熟悉是因为只要你是做开发,都会用到注解(常见的@Overrid...
    _Justin阅读 1,344评论 0 10
  • 读完村上大叔的《当我跑步时谈些什么》,不由得感叹,大家就是大家啊,跑个步都能洋洋洒洒的写成一本书,大叔你的脑...
    哈哈的情感故事铺子阅读 217评论 0 1
  • 故里第一次遇见南昭的时候,是十二月。北方的小城里,冷的要命。那个时候,她的心也是冷的。 而南昭,和她远隔千里,在一...
    似里阅读 218评论 0 1