基础加强:注解

来源:互联网 发布:男性特点知乎 编辑:程序博客网 时间:2024/06/05 09:23
----------------------android培训java培训、期待与您交流! ---------------------- 
英语角:
retention: 保留
Inherited:继承
suppress:抑制
documented:记录
parameter:参数
attribute:属性
dimention:维度
struts:     (框架的)支杆,支柱
hibernate: 冬眠,蛰伏

一、注解的特点和种类
1、注解的特点:

  1)所有的注解类型都继承了java.lang.annotation.Annotation这个公共接口 (接口的继承性),说所有注解类型是继承而不是实现说明所有注解的类型本质就是接口。源码如下:

public interface Annotation { boolean equals(Object obj); int hashCode(); String toString(); Class<? extendsAnnotation> annotationType();}

  2)注解通常单独放置在一行,不影响程序代码的执行。无论是增加或者删除注解,代码都始终执行。
  3)默认情况下,注解可以修饰程序中的任何成分。也可以通过@Target来修饰这个注解改变这个注解的作用范围。

注解按照使用方式可以分为三种:内建注解、元注解、自定义注解
2、内建注解:位于java.lang包,有三种
  • 限定重写:@Override
  • 标记过时:@Deprecated
  • 抑制警告:@Suppresswarning
  1)@Override:持续到java源文件阶段。编译之后,被javac就会抛弃。只能修饰方法,用来提示开发者该方法需要被重写,如果没有被重写,编译报错。
  2)@Deprecated:持续到内存字节码阶段。可以修饰八种程序元素中的任意一种,被修饰的程序元素会被打上下划线表示该程序元素过时。只有持续到内存字节码阶段,其他人拿到字节码文件通过反射获取其中的程序元素时才能看到过时信息。
  3)@Suppresswarning:持续到java源文件阶段。编译之后,被javac抛弃。除了包PACKAGE,其他程序元素都能被@SuppressWarnings修饰。用来抑制javac产生“黄色”警告。
  4)三种内建注解的相同点:

  • 三种内建注解都被@Retention和@Target来修饰,@Deprecated又被@Documented修饰,可以被javadoc来是识别
  • 三种内建注解只有@Deprecated的生命周期被保留到内存字节码阶段,其余三种的生命周期是Java源文件阶段。
  • 只有@SuppressWarnings这个注解有一个value的属性变量,字符串数组类型的
3、元注解:位于java.lang.annotation包,有四个。用于修饰其他注解。被元注解修饰的注解作用范围、生命周期、是否被javadoc识别
1)四种元注解各自特点:
(1)@Target:指定被修饰的注解适用范围被修饰的注解只能修饰指定程序元素。
      @Target中value取值范围为一个Element_Type[ ]数组。数组中有8个元素,代表不同的适用范围。
 ElementType枚举类源码:

package java.lang.annotation;public enum ElementType { TYPE, FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE}

  • TYPE:类类型、接口类型 (注解类型)、枚举类型声明
  • FIELD:成员属性声明 (包括枚举常量成员)
  • METHOD成员方法声明
  • PARAMETER:参数声明
  • CONSTRUCTOR:构造方法声明
  • LOCAL_VARIABLE:局部变量声明
  • ANNOTATION_TYPE:注解类型声明
  • PACKAEG:包声明

(2)@Retention:用来描述被修饰注解的生命周期。取值是枚举类型RetentionPolicy类型,有三个。
ElementType枚举类源码

package java.lang.annotation;public enum RetentionPolicy { SOURCE, CLASS, RUNTIME}

SOURCE:表示被修饰的注解的生命周期持续到源文件阶段,Javac编译完成之后就丢弃

CLASS:成员属性声明 (包括枚举常量),被@Retention修饰的注解Javac编译完成之后会保留,在字节码被JVM运行时丢 弃。注意:@Retention的value的默认取值就是RetentionPolicy.CLASS。

RUNTIME:成员方法声明,被@RUNTIME修饰的注解一直被保留到JVM运行时。

(3)@Documented:被修饰的注解被javadoc工具提取成文档
(4)@Inherited:被修饰注解具有继承性。如果某个类使用了被@Inherited修饰的注解,那么这个类的子类自动继承这个被@Inherited修饰的注解
2)四种元注解的相同点

  • 对于@Documented@Retention@Target可以相互修饰也可以修饰自身
  • @Inherited也被其他三种元注解修饰,但是他不修饰其他元注解也不修饰自身。
  • 四种元注解生命周期都是到内存字节码阶段四种元注解修饰范围只能是注解,不能修饰非注解元素。
  • 四种元注解都能被javadoc工具识别并提取成文档。
4、自定义注解
1)格式:public @interface注解名{…}
2)特点:
(1)定义时,注解内的成员方法默认public abstract,且一定要是空参的不抛出异常的方法。
因为接口中的成员变量默认为public static final是全局常量,如果用接口中的成员变量来定义注解的属性,那么程序中多有被同一个注解修饰的元素都具有相同的属性,这不是我们需要的,我们需要为不同的程序元素添加不同的属性,从而使JVM做不同的操作,所以定义时,不能用成员变量来进行,而是使用成员方法。
(2)访问时,以成员变量的形式来进行访问。
因为,注解只是起一个标记的作用,虽然用成员方法来定义属性,但是在实际使用时,不需要对方法体进行复杂的实现,就用一个不同的值来表示不同的属性而已,为了简化书写调用时,将@注解名(value( ){抽象方法的实现体}) 简化为@注解名(value =返回值类型的值)。

//定义时

public @interface MyAnnotation{

String name();

}

//访问时

@MyAnnotation(color="red")

3)为注解添加属性
(1)为注解的成员变量设置默认值:在抽象方法名“( )”之后和“;”之前,使用default关键字来设置默认的初始值。如下:

@interface MyAnnotation{ String name() default "Mike"; int age();}

在其他类上使用这个注解,name属性不指定初始值(因为在注解类定义的时候,已经为这个成员变量设置了默认值),但是age必须制定初始值,因为接口中的方法必须被实现。不过在使用该注解时可以根据需要设置新的属性覆盖掉默认值。如下:

@MyAnnotation(name="John", age=18)public class AnnotationTest{}

(2)调用注解时省略变量名的情况
  • 注解的定义只有一个抽象方法且方法名为value的时候,可以在调用这个注解的时候省去变量名直接赋值。如果这个方法名不是value的话,会报错并提示"Creat attribute value()"。如下:
黑马程序员——Java基础加强笔记:注解 - 1340743130 - 李维林的博客
 
  • 如果注解定义中有多个方法,但是除了一个value()以外,其他方法全部都有默认值,此时也可以直接对value()进行赋值。

package cn.itheima;@interface AnnotationOne{String color() default "red";int value();}@AnnotationOne(100)public class MyAnnotation {public static void main(String[] args) {// TODO Auto-generated method stub}}

4)为注解增加高级属性
(1)为注解增加数组属性

//定义含有数组属性的注解

@interface AnnotationArray { int[] arr() default {4, 5, 6};}

//调用该注解并为注解赋新值
@AnnotationArray(arr ={1, 2, 3})class AnnotationArrayTest{}
//利用反射测试新值是否赋值成功
@AnnotationArray(arr={1,2,3})public class MyAnnotation {
public static void main(String[] args) { if(MyAnnotation.class.isAnnotationPresent(AnnotationArray.class)){ AnnotationArray AnArr =(AnnotationArray)MyAnnotation.class .getAnnotation(AnnotationArray.class);printArr(AnArr.arr());}}public static void printArr(int[] arr){for (int i : arr) {System.out.println(i);}}
}
//输出结果:1 23 赋值成功。
注意:注解中数组设置默认值和调用的时候,仅接受“{ }”定义的初始值,不接受new关键字声明的数组。否则编译错误。
(2)为注解增加枚举属性

package cn.itheima;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;// 自定义Gender枚举类型enum Gender{ male(1), female(0); private int genderIndex =-1; private Gender(int genderIndex){ this.genderIndex =genderIndex; }}

//为注解设定生命周期,便于反射调用@Retention(value=RetentionPolicy.RUNTIME)

//自定义含有Gender枚举类型的注解类型@interface AnnotationEnum{ Gender gender() default Gender.male;}

//调用这个含有枚举类型的属性的注解类@AnnotationEnum(gender =Gender.female)public class MyAnnotation2 { public static void main(String[] args) {if(MyAnnotation2.class.isAnnotationPresent(AnnotationEnum.class)){ AnnotationEnum AnEnum = (AnnotationEnum)MyAnnotation2.class.getAnnotation(AnnotationEnum.class);System.out.println(AnEnum);}}}

(3)为注解增加注解属性

package cn.itheima;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;enum Gender{ male, female;}

@interface AnnotationEnum{ Gender gender() default Gender.male;}

//为注解设定生命周期,便于反射调用@Retention(value=RetentionPolicy.RUNTIME)

//使用这个AnnotationAnno作为另一个注解中的成员变量@interface AnnotationAnno{AnnotationEnum anEnum () default @AnnotationEnum(gender =Gender.female);//注意写法,@不能丢。}

//调用这个含有注解类型的属性的注解类@AnnotationAnno()public class MyAnnotation2 { public static void main(String[] args) { if(MyAnnotation2.class.isAnnotationPresent(AnnotationAnno.class)){AnnotationAnno AnAnuo = (AnnotationAnno)MyAnnotation2.class.getAnnotation(AnnotationAnno.class);System.out.println(AnAnuo);}}}

4)反射操作注解对象
(1)AnnotatedElement接口简介
AnnotatedElement接口专门用于使用反射操作注解, 已知实现子类:AccessibleObject , Class, Package
由于注解是一种标记,仅仅是用来修饰其他程序元素的,因此注解不能单独使用,要依附于具体的程序元素才能使用。所以,让相应的程序片段对应的反射的类(AccessibleObject,Constructor, Filed, Method, Class, Package)去实现AnnotatedElement接口表示这些类的对象通过自身就有能力用反射来来判断自身(程序元素)是否含有注解。
(2)常见操作
  • 判定是否存在某一种指定类型的注解
boolean  isAnnotationPresent(Class<?extends Annotation>annotationClass);
  • 获取指定类型的注解对象
<T extends Annotation>T  getAnnotation(Class<T> annotationClass)
  • 返回出现在这个程序元素上所有的注解(直接或者间接的都算)
Annotation[ ]   getAnnotations()
  • 返回直接出现在这个程序元素上所有的注解(间接的不算)
Annotation[ ]   getDeclaredAnnotations();

注意:使用反射的操作注解的时候,这个注解的生命周期一定要到运行时期。需要对这个注解用元注解@Retention进行修饰,并且把@Retention的成员属性value的值设定为RetentionPolicy.RUNTIME。否则,由于注解默认的是维持到字节码阶段。这样在装载.class文件的时候,这些注解就要被去掉,反射技术无法访问到这些字节码文件注解。
0 0
原创粉丝点击