有些同学向我反映,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 一定要自己完成一遍……. 搞明白了这个例子,那么你对注解的掌握就完成了一大半,为什么笔者不写其他牛的例子,而只写如何使用注解获取类的所有信息的例子,因为你只要通过注解获取到类的所有信息,那么很多框架,包括自己想写框架,在你一次次写注解的时候,你就慢慢掌握啦! |
|