黑马程序员-高新技术(注解)

来源:互联网 发布:鲜花网络销售 编辑:程序博客网 时间:2024/06/06 01:08

-----------android培训java培训、java学习型技术博客、期待与您交流! ------------


一、概述


注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则没有某种标记。
以后java编译器、开发工具和其他应用程序就可以用反射来了解自己的类及各种元素上有无何种
标记,有什么标记,就会做出相应的处理。标记可以加在包、类、字段、方法、方法参数,以及
局部变量上等等。在java.lang包中提供了最基本的annotation,即注解。

格式:@注解类名()。如果有属性,则在括号中加上属性名(可省略)和属性值。

二、java中三种最基本的注解


1、@SuppressWarning(”deprecation”)--->压制警告

SupressWarning是告知编译器或开发工具等提示指定的编译器警告;
”deprecation”是告知具体的信息即方法已过时。

2、@Deprecated--->提示成员等已经过时,不再推荐使用。

源代码标记@Deprecated是在JDK1.5中作为内置的annotation引入的,用于表明类(class)、方法(method)、字段(field)已经不再推荐使用,并且在以后的JDK版本中可能将其删除,编译器在默认情况下检测到有此标记的时候会提示警告信息。
例如:假定之前的某个类升级了,其中的某个方法已经过时了,不能够将过时的方法删除,因为可能会影响到调用此类的这个方法的某些程序,这是就可以通过在方法上加这个注解。

3、@Override--->提示覆盖(父类方法)

加上此注解,,可对自己类中的方法判断是否是要覆盖的父类的方法,典型的例子即在集合中覆盖equals(Object obj)方法,其中的参数类型必须是Object,才能被覆盖,若不是,加上此注解就会提示警告。

三、注释的应用--->注解类


1、定义格式

@interface 名称{statement}

2、元注解(注解的注解)

一个注解有其生命周期(Retetion)和存放的位置(Taget),这就可以通过元注解说明。


(1)Retetion


Retetion用于说明注解保留在哪个时期,加载定义的注解之上。

一个注解的声明周期包含:
java源程序--(javac)-->class文件--(类加载器)-->内存中的字节码
第一、当再源程序上加了注解,javac将java源程序编译为class文件,可能会把源程序中的一些注解去掉,进行相应的处理操作,当我们拿到源程序的时候,就看不到这些注解了。
第二、假设javac把这些注解留在了源程序中(或者说留在了class文件中),当运行此class文件的时候,用类加载器将class文件调入内存中,此时有转换的过程,即把class文件中的注解是否保留下来也不一定。

注意:class文件中不是字节码,只有把class文件中的内部加载进内存,用类加载器加载处理后(进行完整的检查等处理),最终得到的二进制内容才是字节码。

Reteton 枚举类取值:
Retetion.Policy.SOURSE:java源文件时期,如@Overried和@SuppressWarning
Retetion.Policy.CLASS: class文件时期(默认阶段)
Retetion.Policy.RUNTIME:运行时期,如@Deprecated

(2)Taget


用于说明注解存放在哪些成分上,默认值是任何元素,其值可设置为枚举类ElementType类中的任何一个,包括:包、字段、方法、方法参数、构造器、类等值。取值为:
PACKAGE(包声明)
FIELD(字段声明)
ANNOTATION_TYPE(注释类型声明)
CONSIRUCTOR(构造器声明)
METHOD(方法声明)
PARAMETER(参数声明)
TYPE(类、接口(包含注释类型)或枚举声明)
LOCAL_VARIABLE(局部变量声明)
注意:其中代表类的值是TYPE。因为class、enum、interface和@interface等都是属于Type的。不可用CLASS表示。

3、通过反射查看其它类中的注释:


过程:
第一、注解类:@interfaceA{}
第二、应用了“注释类”的类:@Aclass B{}
第三、对“应用注释类的类”进行反射操作的类:class{...},操作如下:

B.class.isAnnotionPresent(A.class);//判断是否存在此注解类
A a = B.class.getAnnotation(a.class);//存在的话则得到这个注释类的对象

代码示例:

@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE,ElementType.METHOD})public @interface ItcastAnnotation {}@ItcastAnnotation()public class AnnotionTest {@SuppressWarnings("deprecation")//表示压制警告的注解@ItcastAnnotation()public static void main(String[] args) {System.runFinalizersOnExit(true);//反射方式查看注解//检查类上是否有注解if(AnnotionTest.class.isAnnotationPresent(ItcastAnnotation.class)){//通过反射获取到注解ItcastAnnotation annotation = AnnotionTest.class.getAnnotation(ItcastAnnotation.class);System.out.println(annotation);}}}

四、为注解增加基本属性


1、属性

一个注解相当于一个胸牌,但仅通过胸牌还不足以区别带胸牌的两个人,这时就需要给胸牌增加一个属性来区分,如颜色等。

2、定义格式

同接口中的方法一样:String color();
定义缺省格式:Stringvalue() default ”ignal”;

3、应用

直接在注解的括号中添加自身的属性,如:@ItcastAnnotation(color=”red”)
这个和上面的@SuppressWarnings("deprecation")是一样的,其中的"deprecation"就是属性值
◇当只有一个属性时,可直接传入属性值。如”red”
◇当含有其他属性值的时候,如果那个属性值是缺省的(default),也可以直接传入这个属性值。

五、为注解增加高级属性


1、可以为注解增加的高级属性的返回值类型有:


◇八种基本数据类型
◇String类型 
◇Class类型
◇枚举类型  
◇注解类型  
◇前五种类型的数组

2、数组类型的属性

定义:int[]arrayArr() default {1,2,3}; --> 可不定义默认值
应用:@MyAnnotation(arrayArr={2,3,4})  --> 可重新赋值
注:若数组属性中只有一个元素(或重新赋值为一个元素),这时属性值部分可省略大括号。

3、枚举类型的属性

假设定义了一个枚举类TraffLamp,它是EnumTest的内部类,其值是交通灯的三色。
定义:EnumTest.TrafficLamplamp();
应用:@MyAnnotation(lamp=EnumTestTrafficLamp.GREEN)

4、注解类型的属性

假定有个注解类:MetaAnnotation,其中定义了一个属性:String value()

定义:MetaAnnotationannotation() default @MetaAnnotation(”xxx”);
应用:@MyAnnotation(annotation=@MetaAnnotation(”yyy”))  --> 可重新赋值

可认为上面的@MetaAnnotation是MyAnnotation类的一个实例对象,
同样可以认为上面的@MetaAnnotation是MetaAnnotation类的一个实例对象,
调用:
MetaAnnotation ma =MyAnnotation.annotation();
System.out.println(ma.value());

5、Class类型的属性:

定义:Class cls();
应用:@MyAnnotation(cls=ItcastAnnotion.class)
注:这里的.class必须是已定义的类,或是已有的字节码对象

6、基本数据类型的属性(以int为例)

定义:int val()default 3;   -->可不定义默认值
应用:@MyAnnotation(val=7)  --> 可重新赋值

实例1:自定义注解类

package cn.itcast.text2;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import cn.itcast.text1.EnumText;//将定义的注解的生命周期设置在运行时期@Retention(RetentionPolicy.RUNTIME)//定义注解的放置位置@Target({ElementType.TYPE,ElementType.METHOD})//自定义注解public @interface ItcastAnnotation {//定义属性String str();int val() default 1;int[] arr() default {2,3,4};Class cls() default AnnotionTest.class;EnumText.TrafficLamp lamp() default EnumText.TrafficLamp.YELLOW;MetaAnnotation annotation() default @MetaAnnotation("sss");}

实例2:测试注解类,用反射查看其属性

package cn.itcast.text2;import cn.itcast.text1.EnumText;@ItcastAnnotation(annotation=@MetaAnnotation("anntation"),Lamp=EnumText.TrafficLamp.RED,arr=7,val=5,str="String",cls=ItcastAnnotation.class)public class AnnotionTest {@SuppressWarnings("deprecation")//表示压制警告的注解@ItcastAnnotation(str = "yyy")//有缺省值可不用写缺省部分public static void main(String[] args) {//反射方式查看注解//检查类上是否有注解if(AnnotionTest.class.isAnnotationPresent(ItcastAnnotation.class)){//通过反射获取到注解ItcastAnnotation annotation = AnnotionTest.class.getAnnotation(ItcastAnnotation.class);//打印查看属性值System.out.println(annotation);System.out.println(annotation.str());System.out.println(annotation.val());System.out.println(annotation.arr().length);System.out.println(annotation.cls().getName());System.out.println(annotation.lamp().nextLamp());System.out.println(annotation.annotation().value());}}}

实例3:定义枚举类,交通灯

package cn.itcast.text1;public class EnumText {public static void main(String[] args) {}//定义交通灯public enum TrafficLamp{//定义3个元素,即此类的子类,覆写抽象方法RED(30){@Overridepublic TrafficLamp nextLamp() {return GREEN;}},GREEN(45){@Overridepublic TrafficLamp nextLamp() {return YELLOW;}},YELLOW(5) {@Overridepublic TrafficLamp nextLamp() {return RED;}};private int time;//构造方法private TrafficLamp(int time){this.time = time;}//抽象方法,转为下个灯public abstract TrafficLamp nextLamp();}}

六、注解总结 


1、定义注解
使用元注解定义注解,元注解有四种:
@Target(ElementType.[type])
[type]={METHOD, FIELD, TYPE(类、接口、枚举声明), CONSTRUCTOR, LOCAL_VARIABLE, PARAMETER}
    
@Retention(RetentionPolicy.[policy])
[policy]={SOURCE, CLASS, RUNTIME(反射机制可读取)}
    
@Documented 表示将此注解包含到Javadoc中
@Inherited 表示允许子类继承父类的注解

2、使用注解
@UserCase(id=10, description="my desccription")
注意:
注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定非基本类型的注解元素的值不可为null
注解快捷方式: 如果注解元素声明为value(),则在使用注解时如果只声明value,可以只写值,不必写名值对。例如可写为@UseCase(10)

3、编写注解处理器
通过反射机制获取注解元素的值: Method.getAnnotation(), Field.getDeclaredAnnotations()等方法

4、注解的使用场景
统计系统用例实现情况    
由JavaBean自动生成数据库建表SQL

5、JDK提供的注解工具apt


6、基于注解的单元测试     
    
7、合理的设计和使用注解
使用注解标记字段和方法,可通过反射的手段截取注解及其标记的字段和方法的元数据,并根据需求对元数据进行处理。它赋予了字段和方法额外的意义,提供了一种统一处理字段和方法的优雅的方式。注解更多的意义是提供了一种设计模式,在本质上它没有增强Java的能力,使用注解实现的功能都可以以非注解的方式实现,只是代码可能不是很好看而已




原创粉丝点击