您好,欢迎访问一九零五行业门户网

Java注解的定义及使用介绍(代码示例)

本篇文章给大家带来的内容是关于java注解的定义及使用介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
java的注解在实际项目中使用得非常的多,特别是在使用了spring之后。
本文会介绍java注解的语法,以及在spring中使用注解的例子。注解的语法
注解的例子
以junit中的@test注解为例
@target(elementtype.method)@retention(retentionpolicy.runtime)public @interface test {    long timeout() default 0l;}
可以看到@test注解上有@target()和@retention()两个注解。
这种注解了注解的注解,称之为元注解。
跟声明了数据的数据,称为元数据是一种意思。
之后的注解的格式是
修饰符 @interface 注解名 {       注解元素的声明1     注解元素的声明2   }
注解的元素声明有两种形式
type elementname();type elementname() default value;  // 带默认值
常见的元注解@target注解@target注解用于限制注解能在哪些项上应用,没有加@target的注解可以应用于任何项上。
在java.lang.annotation.elementtype类中可以看到所有@target接受的项
type 在【类、接口、注解】上使用
field 在【字段、枚举常量】上使用
method 在【方法】上使用
parameter 在【参数】上使用
constructor 在【构造器】上使用
local_variable 在【局部变量】上使用
annotation_type 在【注解】上使用
package 在【包】上使用
type_parameter 在【类型参数】上使用 java 1.8 引入
type_use 在【任何声明类型的地方】上使用 java 1.8 引入
@test注解只允许在方法上使用。
@target(elementtype.method)public @interface test { ... }
如果要支持多项,则传入多个值。
@target({elementtype.type, elementtype.method})public @interface myannotation { ... }
此外元注解也是注解,也符合注解的语法,如@target注解。
@target(elementtype.annotation_type)表明@target注解只能使用在注解上。
@documented@retention(retentionpolicy.runtime)@target(elementtype.annotation_type)public @interface target {    elementtype[] value();}
@retention注解@retention指定注解应该保留多长时间,默认是retentionpolicy.class。
在java.lang.annotation.retentionpolicy可看到所有的项
source 不包含在类文件中
class 包含在类文件中,不载入虚拟机
runtime  包含在类文件中,由虚拟机载入,可以用反射api获取
@test注解会载入到虚拟机,可以通过代码获取
@retention(retentionpolicy.runtime)public @interface test { ... }
@documented注解主要用于归档工具识别。被注解的元素能被javadoc或类似的工具文档化。
@inherited注解添加了@inherited注解的注解,所注解的类的子类也将拥有这个注解
注解
@target(elementtype.method)@retention(retentionpolicy.runtime)@inheritedpublic @interface myannotation { ... }
父类
@myannotation class parent { ... }
子类child会把加在parent上的@myannotation继承下来
class child extends parent { ... }
@repeatable注解java 1.8 引入的注解,标识注解是可重复使用的。
注解1
public @interface myannotations {       myannotation[] value();   }
注解2
@repeatable(myannotations.class)public @interface myannotation {       int value();}
有使用@repeatable()时的使用
@myannotation(1)@myannotation(2)@myannotation(3)public class mytest { ... }
没使用@repeatable()时的使用,@myannotation去掉@repeatable元注解
@myannotations({    @myannotation(1),     @myannotation(2),    @myannotation(3)})public class mytest { ... }
这个注解还是非常有用的,让我们的代码变得简洁不少,
spring的@componentscan注解也用到这个元注解。
元素的类型支持的元素类型8种基本数据类型(byte,short,char,int,long,float,double,boolean)
string
class
enum
注解类型
数组(所有上边类型的数组)
例子枚举类
public enum status {    good,    bad}
注解1
@target(elementtype.annotation_type)public @interface myannotation1 {    int val();}
注解2
@target(elementtype.type)public @interface myannotation2 {        boolean boo() default false;        class<?> cla() default void.class;        status enu() default status.good;        myannotation1 anno() default @myannotation1(val = 1);        string[] arr();    }
使用时,无默认值的元素必须传值
@myannotation2(        cla = string.class,        enu = status.bad,        anno = @myannotation1(val = 2),        arr = {a, b})public class mytest { ... }
java内置的注解@override注解告诉编译器这个是个覆盖父类的方法。如果父类删除了该方法,则子类会报错。
@deprecated注解表示被注解的元素已被弃用。
@suppresswarnings注解告诉编译器忽略警告。
@functionalinterface注解java 1.8 引入的注解。该注释会强制编译器javac检查一个接口是否符合函数接口的标准。
特别的注解有两种比较特别的注解
标记注解 : 注解中没有任何元素,使用时直接是 @xxxannotation, 不需要加括号
单值注解 : 注解只有一个元素,且名字为value,使用时直接传值,不需要指定元素名@xxxannotation(100)
利用反射获取注解java的annotatedelement接口中有getannotation()等获取注解的方法。
而method,field,class,package等类均实现了这个接口,因此均有获取注解的能力。
例子注解@retention(retentionpolicy.runtime)@target({elementtype.type, elementtype.field, elementtype.method})public @interface myanno {       string value();   }
被注解的元素@myanno(class)public class myclass {        @myanno(feild)    private string str;        @myanno(method)    public void method() { }    }
获取注解public class test {        public static void main(string[] args) throws exception {            myclass obj = new myclass();        class<?> clazz = obj.getclass();                // 获取对象上的注解        myanno anno = clazz.getannotation(myanno.class);        system.out.println(anno.value());                // 获取属性上的注解        field field = clazz.getdeclaredfield(str);        anno = field.getannotation(myanno.class);        system.out.println(anno.value());                // 获取方法上的注解        method method = clazz.getmethod(method);        anno = method.getannotation(myanno.class);        system.out.println(anno.value());    }    }
在spring中使用自定义注解注解本身不会有任何的作用,需要有其他代码或工具的支持才有用。需求设想现有这样的需求,程序需要接收不同的命令cmd,
然后根据命令调用不同的处理类handler。
很容易就会想到用map来存储命令和处理类的映射关系。
由于项目可能是多个成员共同开发,不同成员实现各自负责的命令的处理逻辑。
因此希望开发成员只关注handler的实现,不需要主动去map中注册cmd和handler的映射。
最终效果最终希望看到效果是这样的
@cmdmapping(cmd.login)public class loginhandler implements icmdhandler {    @override    public void handle() {        system.out.println(handle login request);    }}@cmdmapping(cmd.logout)public class logouthandler implements icmdhandler {    @override    public void handle() {        system.out.println(handle logout request);    }}
开发人员增加自己的handler,只需要创建新的类并注上@cmdmapping(cmd.xxx)即可。
具体做法具体的实现是使用spring和一个自定义的注解
定义@cmdmapping注解
@documented@target(elementtype.type)@retention(retentionpolicy.runtime)@componentpublic @interface cmdmapping {    int value();   }
@cmdmapping中有一个int类型的元素value,用于指定cmd。这里做成一个单值注解。
这里还加了spring的@component注解,因此注解了@cmdmapping的类也会被spring创建实例。
然后是cmd接口,存储命令。
public interface cmd {    int register = 1;    int login    = 2;    int logout   = 3;}
之后是处理类接口,现实情况接口会复杂得多,这里简化了。
public interface icmdhandler {     void handle();   }
上边说过,注解本身是不起作用的,需要其他的支持。下边就是让注解生效的部分了。
使用时调用handle()方法即可。
@componentpublic class handlerdispatcherservlet implements     initializingbean, applicationcontextaware {    private applicationcontext context;    private map<integer, icmdhandler> handlers = new hashmap<>();        public void handle(int cmd) {        handlers.get(cmd).handle();    }        public void afterpropertiesset() {                string[] beannames = this.context.getbeannamesfortype(object.class);        for (string beanname : beannames) {                        if (scopedproxyutils.isscopedtarget(beanname)) {                continue;            }                        class<?> beantype = this.context.gettype(beanname);                        if (beantype != null) {                                cmdmapping annotation = annotatedelementutils.findmergedannotation(                        beantype, cmdmapping.class);                                if(annotation != null) {                    handlers.put(annotation.value(), (icmdhandler) context.getbean(beantype));                }            }        }            }    public void setapplicationcontext(applicationcontext applicationcontext)            throws beansexception {           this.context = applicationcontext;    }}
主要工作都是spring做,这里只是将实例化后的对象put到map中。
测试代码
@componentscan(pers.custom.annotation)public class main {    public static void main(string[] args) {                annotationconfigapplicationcontext context             = new annotationconfigapplicationcontext(main.class);                    handlerdispatcherservlet servlet = context.getbean(handlerdispatcherservlet.class);                servlet.handle(cmd.register);        servlet.handle(cmd.login);        servlet.handle(cmd.logout);        context.close();    }}
> 完整项目
总结可以看到使用注解能够写出很灵活的代码,注解也特别适合做为使用框架的一种方式。
所以学会使用注解还是很有用的,毕竟这对于上手框架或实现自己的框架都是非常重要的知识。
以上就是java注解的定义及使用介绍(代码示例)的详细内容。
其它类似信息

推荐信息