java标注_java注解

注解概念与注解的作用

注解定义:注解是一种元数据,是在jdk1.5以及以后的版本引入的,与类,接口,枚举在同一层次的,它可以声明在一个类,方法,属性等前面,用来对这些元素进行说明,解释。

注解的作用:

编写文档:通过代码标识的注解,来生成文档(doc文档,api文档)

代码分析:通过代码标识的注解,来对代码进行分析(反射)

编译检查:通过代码标识的注解,来对代码进行编译前的检查(Override注解)

注解的本质

通过自定义一个注解AnnoDemo 里面含有一个name属性,然后对AnnoDemo的class文件进行反编译得到如下内容:

cc3957146f6105b1325ae30eb1ad94a7.png

从上面结果看出,AnnoDemo注解本质是一个继承java.lang.annotation.Annotation接口的一个接口,注解AnnoDemo属性name,本质上是一个抽象方法。具体自定义注解规则在下面自定义注解再将。

自定义注解

自定义注解的语法:@interface 注 名{ 注解属性列表}

属性和属性取值类型:属性就是指接口中的抽象方法:属性取值类型可以是八大基本类型,String类型,枚举类型,注解,以及上面三种类型的数组

注解使用:如果注解定义了属性,在使用时需要给属性赋值操作,有以下注意事项:如果定义属性时,用default 给属性一个默认值,那么使用注解时,可以不给属性赋值操作,如果注解只定义一个属性时,并且属性名为value,使用注解时,对属性赋值,可以省去属性名=,可以直接定义值。数组属性赋值操作规则为{值1,值2 ...}

自定义注解一般需要用到元注解,元注解指的是描述注解的注解,在下面会介绍jdk的四大元注解:

jdk四大元注解

@Target:注解作用的位置

@Retention:注解的生命周期

@Documented:注解是否应当被包含在 JavaDoc (api)文档中

@Inherited:是否允许子类继承该注解

其中,@Target 指的是注解是作用在类上,还是方法,属性上。@Target注解定义如下:

3fcc1523243f59f02a9482974b1d6b39.png

通过ElementType 这个枚举类型的值,指定作用的位置,ElementType有以下一些值:

ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上

ElementType.FIELD:允许作用在属性字段上

ElementType.METHOD:允许作用在方法上

ElementType.PARAMETER:允许作用在方法参数上

ElementType.CONSTRUCTOR:允许作用在构造器上

ElementType.LOCAL_VARIABLE:允许作用在本地局部变量上

ElementType.ANNOTATION_TYPE:允许作用在注解上

ElementType.PACKAGE:允许作用在包上

@Retention 用于指明当前注解的生命周期,定义如下:

b2240df1dc538cbe039d1fba8866faac.png

通过 RetentionPolicy 这个枚举类型的值,指定注解的生命周期,RetentionPolicy有以下取值:

RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件

RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件

RetentionPolicy.RUNTIME:永久保存,可以反射获取

@Retention 注解指定了被修饰的注解的生命周期,一种是只能在编译期可见,编译后会被丢弃,一种会被编译器编译进 class 文件中,无论是类或是方法,乃至字段,他们都是有属性表的,而 JAVA 虚拟机也定义了几种注解属性表用于存储注解信息,但是这种可见性不能带到方法区,类加载时会予以丢弃,最后一种则是永久存在的可见性。

剩下两种类型的注解我们日常用的不多,也比较简单,这里不再详细的进行介绍了,你只需要知道他们各自的作用即可。@Documented 注解修饰的注解,当我们执行 JavaDoc 文档打包时会被保存进 doc 文档,反之将在打包时丢弃。@Inherited 注解修饰的注解是具有可继承性的,也就说我们的注解修饰了一个类,而该类的子类将自动继承父类的该注解。

常用的java内置注解

@Override:  该注解标注的方法必须继承父类(接口),否则编译不通过。该注解定义如下:

6649034d80a57dc448e674cf44ce0625.png

@Deprecated: 该注解标注的代码(方法),表示这些代码已经过时了,该注解定义如下:

a4784f2a5912f4675022b4e7421720b2.png

@SuppressWarinings:该注解标注的代码,如果有警告,会压制警告。使用该注解时,一般给value属性赋值all,该注解定义如下:

eb66144ae941441a3dd3dfca8ae3396b.png

注解案例

自定义一个StudentAnno注解代码如下:

//自定义枚举类型AnnoStudent

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documentedpublic @interfaceAnnoStudent {intage();

String name();

String [] course();

Target anno();

Grade grade();

}//枚举类Grade

public enumGrade {

SMALL,MID,HIGH;

}//测试类

@AnnoStudent(age=15,name="jack",course={"Enlish","Math"},anno = @Target(ElementType.ANNOTATION_TYPE),grade=Grade.HIGH

)public classTestAnno {

}

定义一个检测注解,检测一个Calculator类的所有方法是否正常运行,如果异常将其记录在一个log文件中,该过程结合了反射:具体代码如下:

//注解类

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documentedpublic @interfaceCheckAnno {

}//如果检测的类/*** 模拟一个计算器类*/

public classCalculator {//加法

@CheckAnnopublic voidadd(){

System.out.println("1+0="+(1+0));

}//减法

@CheckAnnopublic voidsub(){

System.out.println("1-0="+(1-0));

}//乘法

@CheckAnnopublic voidmulti(){

System.out.println("1*0="+(1*0));

}//除法

@CheckAnnopublic voiddiv(){

System.out.println("1/0="+(1/0));

}

}/***检查计算器类方法是否正常运行,如果不正常运行的方法,将异常的方法,异常的名称,异常的原因记录在checkLog文件中*/

public classTestCheck {public static void main(String[] args )throwsIOException {

Calculator c=newCalculator();//获取计算类的字节码

Class cla =c.getClass();//获取计算器类的所有定义的方法

Method [] methodss=cla.getDeclaredMethods();int num=0;//出现异常的方法数

BufferedWriter bw=new BufferedWriter(new FileWriter("checkLog.txt"));for(Method method:methodss){//判断当前方法是否使用Check注解

if( method.isAnnotationPresent(CheckAnno.class)){try{//调用计算器的方法

method.invoke(c);

}catch(Exception e) {//异常处理

bw.write("出现异常的方法:"+method.getName());

bw.newLine();

bw.write("异常的名称:"+e.getCause().getClass().getSimpleName());

bw.newLine();

bw.write("异常的原因:"+e.getCause().getMessage());

bw.newLine();

num++;

}

}

}

bw.write("调用该方法一共出了"+num+"次异常");

bw.close();

}

}

注解与反射结合,获取任意类的对象,调用对象的任意方法,注解相当于配置文件的左右,代码如下:

//注解

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

@Documentedpublic @interfaceReflectAnno {

String className();

String classMethod();

}//测试注解与反射的类/*** 注解与反射结合,获取任意类的对象,并调用该对象的任意方法

* 注解相当与配置文件*/@ReflectAnno(className= "cn.ck.annotation.Student",classMethod = "show")public classReflectTest {public static void main(String[] args) throwsException {//获取相应的注解对象

ReflectAnno ra= ReflectTest.class.getAnnotation(ReflectAnno.class);//注解对象调用相应的抽象方法获取classname属性值,classMethod属性值

String classMethod=ra.classMethod();

String className=ra.className();//将类加载进内存

Class cla=Class.forName(className);//创建对象

Object obj=cla.newInstance();//通过classMethod值,获取相应的方法

Method method=cla.getDeclaredMethod(classMethod);//调用方法

method.invoke(obj);

}

}

Class 类中提供了以下一些方法用于反射注解。

getAnnotation:返回指定的注解

isAnnotationPresent:判定当前元素是否被指定注解修饰

getAnnotations:返回所有的注解

getDeclaredAnnotation:返回本元素的指定注解

getDeclaredAnnotations:返回本元素的所有注解,不包含父类继承而来的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值