本篇文章给大家带来的内容是关于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注解的定义及使用介绍(代码示例)的详细内容。