分享

浅谈———Java注解详解

 谔谔热 2017-08-12

有些同学向我反映,Java注解老是整不明白,那么笔者就专门写篇文章来带同学们学习学习,顺便笔者也复习一下。

Java注解详解

Java中的注解可不是注释,注意区别。Java注解是跟编译器直接挂钩,在JDK1.5之后就出现了注解,那么注解究竟是干嘛的呢?开发者把它开发出来是为了干什么的呢?

1.生成文档。这是最常见的,也是java最早提供的注解。常用的有@see@param@return等,这点都很熟悉,不就是生成自己的API嘛。

2.跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring2.5开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。

3.在编译时进行格式检查。如@Override放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

所以要想成为一名优秀的Java开发程序员,注解的掌握那是必须的。

1.Java中自带的注解

@Override

子类对父类方法的重写所带的注解,这个笔者就不多说啦!简单

@Deprecated

表示已经过时,不建议使用,但是依然可以使用

比如你在调用Thread类的stop方法的时候出现一条横杠,这就是加了@Deprecated的效果,我截个图给你看看:

这条杠是编译器告诉你此方法已经过时啦,所以加条杠提示你一下,但是依然可以调用,并不是不能使用,而是建议不要使用。

@SuppressWarnings

用来抑制编译时的警告信息,编译器在你写代码的时候,难免会出现很多的警告,有强迫症的程序猿会感到极其不爽,那么肿么办呢?@SuppressWarnings注解就可以告诉编译器,别警告啦,代码不会有问题的。

比如你想把调用Thread的stop方法的警告去掉,那么你就可以这么写:

有的同学可能不理解@SuppressWarnings(“all”)中的”all”是啥意思?其实很简单,@SuppressWarnings注解一定要传递一个参数给它,来表示过滤掉哪些类型的警告,笔者添加了”all”表示过滤掉所有类型的警告,很好理解吧!那么还可以传递什么参数来过滤警告呢?看看下面的表格你就会知道啦:

还有一些其它的Java自带注解,笔者就不一一说明了。

2.自定义注解

在学会自定义注解之前,我们必须先来理解一下Java当中用来给自定义注解而注解的元注解,有点绕口哈!没关系,其实很简单,就是说你要自定义一个注解,你必须说明一下这个自定义的注解的使用范围以及保存注解信息,还有是否包含于Javadoc中,是否允许子类继承父类中的注解。这4点分别对应这4种元注解,看下面的表格你就懂啦:

Java4种元注解表格

自定义注解使用关键字@interface,这跟接口有点像,只不过一个”@”符号的差别,还有就是Java注解不支持继承,示例代码如下:

@Target(value={ElementType.METHOD})//这里表示此注解只能被使用于方法

@Retention(RetentionPolicy.RUNTIME)//通常默认使用RUNTIME

@Documented

@Inherited

public@interfaceMyAnnotation{

/*注意在注解当中属性声明是:

*类型+属性名;

*不是声明一个方法,这一定要区别开来

*/

Stringstr;//注解的属性声明,属性类型为String,名字是'str'

}

参考元注解表格,使用”@interface”关键字声明,注意属性的声明末尾是有””的。还有一点就是注解的元素(属性)只支持:

1.所有的基本类型

2.String

3.Class

4.enum

5.Annotation

6.String,Class,enum,Annotation以及基本类型数组

其他的类型都会报错

学会声明了,那么如何使用这个注解呢?示例代码如下:

//@MyAnnotation(str='王者荣耀')用在声明类这里是报错的,因为笔者的注解@MyAnnotation只能用于方法

publicclassStudent{

publicStringname;

publicintage;

@MyAnnotation(str='王者荣耀')//用在这里不会报错

publicvoidplayAndroidGame{

System.out.println(this.name+'玩王者荣耀!');

}

}

目前的注解好像用途并没有完全体现出来,因为你没有为注解添加注解处理器,没有添加注解处理器的注解跟注释没任何区别,所以我们必须为注解添加一个注解处理器,才能让注解的真正用途体现出来,这需要反射的知识,如果你对反射不熟,那么注解处理器怕是有些困难。

3.通过反射创建和使用注解器

讲解注解器需要一个实例作为参考,我们来设计这么一个注解器,可以通过注解器来获取某个类的所有信息。一个类里面会存在属性,方法,内部类,构造函数等,那么我们如何通过注解的方式去获取到一个类的所有信息呢?首先来设计我们的注解:

类的注解:元素(属性)仅包含类名

@Target(value=ElementType.TYPE)//使用范围类,接口,enum等

//要想通过反射获取这个注解信息,此注解一定要保留于运行期,所以这里@@Retention必须是RUNTIME的

@Retention(RetentionPolicy.RUNTIME)

public@interfaceClassAnnotation{

StringclassName;//类的名字

}

类的属性的注解:元素(属性)包含–>属性名,访问权限,属性类型

@Target(value=ElementType.FIELD)//使用于类的成员属性

@Retention(RetentionPolicy.RUNTIME)

public@interfaceFieldAnnotation{

StringfieldName;//属性的名字

StringaccessPer;//访问权限

StringfieldType;//属性的类型

}

方法的注解:元素(属性)包含–>方法名,参数列表,返回值类型,访问权限,方法的功能

@Target(value=ElementType.METHOD)//使用于方法

@Retention(RetentionPolicy.RUNTIME)

public@interfaceMethodAnnotation{

StringmethodName;//方法的名字

ClassparameterList;//参数列表

StringreturnType;//返回值类型

StringaccessPer;//访问权限

StringmethodFunction;//方法的功能描述

}

构造器的注解:元素(属性)包含–>构造器的名名,参数列表,返回值类型,访问权限

@Target(value=ElementType.CONSTRUCTOR)//使用于构造器

@Retention(RetentionPolicy.RUNTIME)

public@interfaceConstructorAnnotation{

StringconName;//构造器的名字

ClassparameterList;//参数列表

ClassreturnType;//返回值类型

StringaccessPer;//访问权限

}

注解已经定义完成,下面一步就是将注解应用于一个类当中,示例代码如下:

importDate20170810.Annotation.ClassAnnotation;

importDate20170810.Annotation.ConstructorAnnotation;

importDate20170810.Annotation.FieldAnnotation;

importDate20170810.Annotation.MethodAnnotation;

@ClassAnnotation(className='Studnet')

publicclassStudent{

@FieldAnnotation(fieldName='name',accessPer='private',fieldType='String')

privateStringname='';

@FieldAnnotation(fieldName='age',accessPer='private',fieldType='int')

privateintage=0;

@ConstructorAnnotation(methodName='Studnet',parameterList={String.class,int.class},

returnType=Student.class,accessPer='public')

publicStudent(Stringname,intage){

this.age=age;

this.name=name;

}

@MethodAnnotation(methodName='getName',parameterList={},returnType=String.class,

accessPer='public',methodFunction='返回当前Student实例对象的名字name')

publicStringgetName{

returnthis.name;

}

@MethodAnnotation(methodName='setName',parameterList={String.class},returnType=Void.class,

accessPer='public',methodFunction='设置当前Student实例对象的名字name')

publicvoidsetName(Stringname){

this.name=name;

}

@MethodAnnotation(methodName='getAge',parameterList={},returnType=int.class,

accessPer='public',methodFunction='返回当前Student实例对象的年龄age')

publicintgetAge{

returnthis.age;

}

@MethodAnnotation(methodName='setAge',parameterList={int.class},returnType=Void.class,

accessPer='public',methodFunction='设置当前Student实例对象的年龄age')

publicvoidsetAge(intage){

this.age=age;

}

@MethodAnnotation(methodName='playAndroidGame',parameterList={},returnType=Void.class,

accessPer='public',methodFunction='王者荣耀有关,就是对小学生玩王者荣耀太厉害的吐槽!')

publicvoidplayAndroidGame{

System.out.println('hello,I'm'+this.name+',今年'+this.age+'岁啦');

if(this.age>12){

System.out.println(this.age+'岁,打王者荣耀还可以不算太坑!');

}else{

System.out.println('由于是小学生,王者排位就算啦,不如来一盘匹配,'+

'排位万万不可!因为啥?怕排位的时候小学生说我辣鸡!');

}

}

}

下面就是通过反射来获取Student类的所有信息啦!示例代码如下:

//注解器

publicclassAnnotatorDemo{

//通过反射获取类的注解信息

publicstaticvoidgetClassAnnotationMessage(Classclass1){

System.out.println('类的注解信息:');

for(java.lang.annotation.Annotationannotation:class1.getDeclaredAnnotations){

System.out.println(annotation);

//获取类注解属性className的值

if(annotation.annotationType.equals(ClassAnnotation.class)){

StringclassName=((ClassAnnotation)annotation).className;

System.out.println('类名:'+className);

}

}

}

//通过反射获取属性的注解信息

publicstaticvoidgetFieldAnnotationMessage(Classclass1){

System.out.println('属性注解的信息:');

Fieldfields=class1.getDeclaredFields;

for(Fieldfield:fields){

System.out.println;

FieldAnnotationfieldAnnotation=field.getDeclaredAnnotation(FieldAnnotation.class);

System.out.println(fieldAnnotation);

//获取属性注解的各种值

StringfieldName=fieldAnnotation.fieldName;

System.out.println('属性名:'+fieldName);

StringaccessPer=fieldAnnotation.accessPer;

System.out.println('属性访问权限:'+accessPer);

ClassfieldType=fieldAnnotation.fieldType;

System.out.println('属性的类型:'+fieldType);

}

}

//获取构造器的注解信息

publicstaticvoidgetConstrutorAnnotationMessage(Classclass1){

System.out.println('构造器注解的信息:');

Constructorconstructors=class1.getDeclaredConstructors;

for(Constructorconstructor:constructors){

System.out.println;

ConstructorAnnotationconstructorAnnotation=constructor.getDeclaredAnnotation(ConstructorAnnotation.class);

System.out.println(constructorAnnotation);

StringconName=constructorAnnotation.conName;

System.out.println('构造器的名字:'+conName);

System.out.print('构造器的参数列表:');

ClassparameterList=constructorAnnotation.parameterList;

for(Classc:parameterList){

System.out.print('['+c.getName+']');

}

System.out.println;

ClassreturnType=constructorAnnotation.returnType;

System.out.println('返回值类型:'+returnType.getName);

StringaccessPer=constructorAnnotation.accessPer;

System.out.println('访问权限:'+accessPer);

}

}

publicstaticvoidgetMethodAnnotationMessage(Classclass1){

System.out.println('方法注解的信息:');

Methodmethods=class1.getDeclaredMethods;

for(Methodmethod:methods){

System.out.println;

MethodAnnotationmethodAnnotation=method.getDeclaredAnnotation(MethodAnnotation.class);

System.out.println(methodAnnotation);

StringmethodName=methodAnnotation.methodName;

System.out.println('方法的名字:'+methodName);

ClassparameterList=methodAnnotation.parameterList;

System.out.print('方法参数参数列表:');

//判断参数列表是否个数为0

if(parameterList.length==0){

//说明此方法无参

System.out.println('无参');

}else{

//说明此方法有参

for(Classc:parameterList){

System.out.print('['+c.getName+']');

}

System.out.println;

}

ClassreturnType=methodAnnotation.returnType;

System.out.println('方法的返回值类型:'+returnType.getName);

StringaccessPer=methodAnnotation.accessPer;

System.out.println('方法的访问权限:'+accessPer);

StringmethodFunction=methodAnnotation.methodFunction;

System.out.println('方法的功能描述:'+methodFunction);

}

}

publicstaticvoidmain(Stringargs){

Classclass_Student=Student.class;

//得到类注解的信息

getClassAnnotationMessage(class_Student);

System.out.println('\n');

//得到属性注解的信息

getFieldAnnotationMessage(class_Student);

System.out.println('\n');

//得到构造器的注解的信息

getConstrutorAnnotationMessage(class_Student);

System.out.println('\n');

//得到方法的注解的信息

getMethodAnnotationMessage(class_Student);

}

运行结果:

类的注解信息:

@Date20170810.Annotation.ClassAnnotation(className=Student)

类名:Student

属性注解的信息:

@Date20170810.Annotation.FieldAnnotation(fieldName=name,accessPer=private,fieldType=classjava.lang.String)

属性名:name

属性访问权限:private

属性的类型:classjava.lang.String

@Date20170810.Annotation.FieldAnnotation(fieldName=age,accessPer=private,fieldType=int)

属性名:age

属性访问权限:private

属性的类型:int

构造器注解的信息:

@Date20170810.Annotation.ConstructorAnnotation(conName=Studnet,parameterList=[classjava.lang.String,int],returnType=classDate20170810.Student,accessPer=public)

构造器的名字:Studnet

构造器的参数列表:[java.lang.String][int]

返回值类型:Date20170810.Student

访问权限:public

方法注解的信息:

@Date20170810.Annotation.MethodAnnotation(methodName=getName,parameterList=,returnType=classjava.lang.String,accessPer=public,methodFunction=返回当前Student实例对象的名字name)

方法的名字:getName

方法参数参数列表:无参

方法的返回值类型:java.lang.String

方法的访问权限:public

方法的功能描述:返回当前Student实例对象的名字name

@Date20170810.Annotation.MethodAnnotation(methodName=setName,parameterList=[classjava.lang.String],returnType=classjava.lang.Void,accessPer=public,methodFunction=设置当前Student实例对象的名字name)

方法的名字:setName

方法参数参数列表:[java.lang.String]

方法的返回值类型:java.lang.Void

方法的访问权限:public

方法的功能描述:设置当前Student实例对象的名字name

@Date20170810.Annotation.MethodAnnotation(methodName=setAge,parameterList=[int],returnType=classjava.lang.Void,accessPer=public,methodFunction=设置当前Student实例对象的年龄age)

方法的名字:setAge

方法参数参数列表:[int]

方法的返回值类型:java.lang.Void

方法的访问权限:public

方法的功能描述:设置当前Student实例对象的年龄age

@Date20170810.Annotation.MethodAnnotation(methodName=playAndroidGame,parameterList=,returnType=classjava.lang.Void,accessPer=public,methodFunction=王者荣耀有关,就是对小学生玩王者荣耀太厉害的吐槽!)

方法的名字:playAndroidGame

方法参数参数列表:无参

方法的返回值类型:java.lang.Void

方法的访问权限:public

方法的功能描述:王者荣耀有关,就是对小学生玩王者荣耀太厉害的吐槽!

@Date20170810.Annotation.MethodAnnotation(methodName=getAge,parameterList=,returnType=int,accessPer=public,methodFunction=返回当前Student实例对象的年龄age)

方法的名字:getAge

方法参数参数列表:无参

方法的返回值类型:int

方法的访问权限:public

方法的功能描述:返回当前Student实例对象的年龄age

一定要自己完成一遍…….

搞明白了这个例子,那么你对注解的掌握就完成了一大半,为什么笔者不写其他牛的例子,而只写如何使用注解获取类的所有信息的例子,因为你只要通过注解获取到类的所有信息,那么很多框架,包括自己想写框架,在你一次次写注解的时候,你就慢慢掌握啦!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多