程序注解是从JavaSE5.0开始提供的一项新特性,利用此特性可以通过特定的注解标签为程序提供一些描述性信息,这些描述信息可以在编译或运行时为编译器、运行环境提供附加的信息,已达到简化开发、避免错误的目的。
简单来说:我们平时用的注释是给人看的,而注解是给机器看的。
下面详细讲解自定义注解及其使用:
1、声明自己的注解
使用某一个注解之前需要声明,就像使用类之前需要声明一样:
@interface <注解名称> { <注解属性类型> <注解属性名称> [default <默认值>]; }
①、“@interface”表示声明的是注解,在“@interface”后面给出注解的名称。
②、一对大括号包含的是注解体,在注解体中可以声明多个注解属性。
③、对注解属性的声明语法比较特殊,注解属性的名称也就是获取次属性值的方法的名称,例如“java.lang.String userName()”表示有一个名称为userName的注解属性,未来需要获取此属性值时调用userName()方法。
④、注解属性的类型一般给出全称类名。
例如:
@interface myAnnotation{ java.lang.String tableName(); int columnNum() default 1; }
上例定义了一个注解,有两个属性:tableName、columnNum,到手后使用反射获取该注解对应的对象后可以通过方法 tableName()和columnNum()获取属性的值,其中属性columnNum有默认值1,如果声明中有默认值,则在使用时可以不指定,否则必须指定属性值。
2、确定注解的使用目标
根据使用目标的不同,注解可以有不同的使用目的,使用目的是指注解起作用的目标元素,可以是类、方法、成员变量,其他注解等。要想为自己声明的注解指定使用目标需要使用系统专门提供的注解"Target",语法:
@Target (ElementType.<使用目标>)
ElementType是java.lang.annotation包中的一个类,其静态成员表示各种不同的使用目标,如下表所示:
静态变量名 | 含义说明 |
ANNOTATION_TYPE | 此注解只能用来对注解进行注解 |
METHOD | 次注解只能用来对方法进行注解 |
CONSTRUCTOR | 此注解只能用来对构造器进行注解 |
PACKAGE | 此注解只能用来对包进行注解 |
FIELD | 此注解只能用来对类成员变量进行注解 |
PARAMETER | 此注解只能用来对参数进行注解 |
LOCAL_VARIABLE | 此注解只能用来对本地变量进行注解 |
TYPE | 此注解只能用来对类、接口以及枚举类型进行注解 |
注意:如果没有为注解指定使用目标,则注解在使用时目标没有限制。 |
例如:
①、先声明两个注解,一个用于类,一个用于属性
用于类的注解声明:
@Target(ElementType.TYPE) @interface ClassAnnotation{ java.lang.String tableName; }
用于属性的注解声明:
@Target(ElementType.FIELD) @interface FieldAnnotation{ java.lang.String columnName; }
②、注解的使用
/** * 狗日的信息实体 * * 注意其中的ClassAnnotation仅用于注释类,FieldAnnotation用于注释属性 * @author js */ @ClassAnnotation(tableName = "tbl_dog") public class DogPojo { @FieldAnnotation(columnName = "dog_name") private String dogName; @FieldAnnotation(columnName = "age") private int age; public String getDogName() { return dogName; } public void setDogName(String dogName) { this.dogName = dogName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
3、确定注解的使用时效
根据使用目的的不同,注解可以有不同的使用时效。使用时效是指注解的有效时间,要想为自己声明的注解指定使用时效,需要使用系统提供的“Retention”注解,语法如下:
@Retention (RetentionPolicy.<时效值>)
RetentionPolicy是java.lang.annotation包中的一个类,时效值由其静态成员变量表示,一共有3种选择,如下表所示:
时效值 | 含义说明 |
CLASS | 注解存在于类文件 |
SOURCE | 注解只存在于源代码中,在编译时被去除 |
RUNTIME | 注解存在于类文件中(编译后仍存在于class字节码文件中,在运行时虚拟机可以获取注解信息) |
4、通过反射提取注解信息
若注解的使用时效为RUNTIME,在运行时可以通过反射来提取注解中的信息。具体方法为:根据需要调用不同使用目标对应的反射类对象提供的getAnnotation方法来获取注解对象的引用,具体语法如下:
<注解名称> 引用 = xxx.getAnnotation(<注解名称>.class);
①、“xxx”表示不同的使用目标对应反射类对象的引用(Method、Field等)。
②、若参数指定的注解类型不存在,则返回null值。
各使用目标与反射类的对应关系如下表所示:
静态变量名 | 含义说明 |
CONSTRUCTOR | java.lang.reflect.Constructor |
METHOD | java.lang.reflect.Method |
FIELD | java.lang.reflect.Field |
PACKAGE | java.lang.Package |
TYPE | java.lang.Class |
5、标注性注解的使用
有时使用注解的目的只是对注解目标进行标注,并不需要注解携带具体的信息,这时只要使用注解目标提供的isAnnotationPresent方法来判断特定注解是否存在即可,方法签名如下:
public boolean isAnnotationPresent(Class annotationClass)
①、方法的入口参数为指定的注解对应的Class类对象引用(注解名.class)。
②、方法的返回值为boolean型,当指定类型的注解存在时返回True,否则返回False。提供isAnnotationPresent方法的常用类有:java.lang.Class、java.lang.Package、java.lang.reflect.AccessiableObject类(AccessiableObject类为Constructor、Field、Method类的父类,因此Constructor、Field、Method类都具有isAnnotationPresent方法)。
根据上面的讲解,下面给出一个详细的使用注解的例子,该例子模仿Hibernate注解实体持久化功能:
①、先分别声明用于注解持久化实体类和属性的注解,用于将实体及其属性映射到数据库表和字段
先定义一个表示数据类型的枚举类,用于表示数据库字段类型:
/** * 定义一个用于表示数据类型的枚举 * * @author js * */ public enum DataTypeEnum { INT,FLOAT,DOUBLE,VARCHAR,DECIMAL }
声明类注解,用于将类映射到表名:
package com.test.my; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 用于指定一个POJO对象映射的表名的注解 * * @author js */ //指定该注解用于注解类 @Target(ElementType.TYPE) //用于指定该注解的使用时效为:存在于class字节码中,运行时可以获取注解信息 @Retention(RetentionPolicy.RUNTIME) public @interface TableAnnotation { /**表名*/ java.lang.String tableName(); }
声明属性注解,用于将类属性与表列关联起来:
package com.test.my; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 用于指定一个字段属性映射的表字段的注解 * * @author js * */ //指定该注解用于注解属性 @Target(ElementType.FIELD) //用于指定该注解的使用时效为:存在于class字节码中,运行时可以获取注解信息 @Retention(RetentionPolicy.RUNTIME) public @interface ColumnAnnotation { /**列名*/ java.lang.String columnName(); /**数据类型,默认为整形*/ com.test.my.DataTypeEnum type() default com.test.my.DataTypeEnum.INT; }
实现Hibernate的实体类持久化功能方法:
package com.test.my; import java.lang.reflect.Field; /** * 对象持久化通用解决方案 * 获取注解上的参数值,动态拼接组装数据 * * @author js */ public class MyHibernate { public void save(Object obj) throws IllegalArgumentException, IllegalAccessException { String tableName = null; String columnSql = null; String valueSql = null; Class objClass = obj.getClass(); TableAnnotation classA = (TableAnnotation)objClass.getAnnotation(TableAnnotation.class); if(null != classA){ tableName = classA.tableName(); } //获取所有的属性并并处理 Field[] fields = objClass.getFields(); for (Field field : fields) { ColumnAnnotation fieldA = field.getAnnotation(ColumnAnnotation.class); if(null == columnSql) { columnSql = fieldA.columnName(); valueSql = (DataTypeEnum.VARCHAR == fieldA.type()) ? ("'"+field.get(obj).toString()+"'") : field.get(obj).toString(); } else { columnSql = columnSql+","+fieldA.columnName(); valueSql = valueSql + "," + ((DataTypeEnum.VARCHAR == fieldA.type()) ? ("'"+field.get(obj).toString()+"'") : field.get(obj).toString()); } } System.out.println("My Hibernate sql:" + "insert into " + tableName + "("+columnSql+") values("+valueSql+")"); } }
好了,我们的注解式Hibernate持久化功能完成了,下面定义两个测试实体测试:
用户信息实体类:
package com.test.my; import com.test.my.DataTypeEnum; /** * 用户信息实体 * 为举例操作简便,使用反射的Field类获取属性值,本类中的所有属性定义为public * 实际使用应该为private,然后使用反射的Method来获取属性值 * * @see MyHibernate * @author js */ @TableAnnotation(tableName = "tbl_user") public class UserPojo { @ColumnAnnotation(columnName = "tbl_id", type = DataTypeEnum.INT) public int id; @ColumnAnnotation(columnName = "tbl_name", type = DataTypeEnum.VARCHAR) public String name; @ColumnAnnotation(columnName = "tbl_id") public int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
角色信息实体类:
package com.test.my; /** * 用户角色信息实体 为举例操作简便,使用反射的Field类获取属性值,本类中的所有属性定义为public * 实际使用应该为private,然后使用反射的Method来获取属性值 * * @see MyHibernate * @author js */ @TableAnnotation(tableName = "tbl_role") public class RolePojo { @ColumnAnnotation(columnName = "tbl_role_id", type = DataTypeEnum.VARCHAR) public String roleId; @ColumnAnnotation(columnName = "tbl_role_name", type = DataTypeEnum.VARCHAR) public String roleName; @ColumnAnnotation(columnName = "tbl_role_params", type = DataTypeEnum.FLOAT) public float params; public String getRoleId() { return roleId; } public void setRoleId(String roleId) { this.roleId = roleId; } public String getRoleName() { return roleName; } public void setRoleName(String roleName) { this.roleName = roleName; } public float getParams() { return params; } public void setParams(float params) { this.params = params; } }
好了,来写个Main函数测试下:
package com.test.my; public class Main { public static void main(String[]args) throws IllegalArgumentException, IllegalAccessException { MyHibernate hibernate = new MyHibernate(); //创建用户信息实体并保存 UserPojo usePojo = new UserPojo(); usePojo.setAge(100); usePojo.setName("张三"); hibernate.save(usePojo); //创建角色信息实体并保存 RolePojo rolePojo = new RolePojo(); rolePojo.setRoleId("00001"); rolePojo.setRoleName("超高级管理员"); rolePojo.setParams(30.1F); hibernate.save(rolePojo); } }
运行,打印的sql语句如下:
呵呵,只要你在实体类中配置好注解,是不是我的这个Hibernate和真正的Hibernate一样很智能了,任何对象实体都可用这一个Hibernate进行保存操作了。
下面再稍微讲讲系统自带的常用注解
6、常用的系统注解
除了前面章节介绍的Target与Retention注解外,系统中还提供了一些指导编译器工作的注解,
①、Override注解:目标为METHOD,使用时效为SOURCE,没有属性,为标注性注解。对方法是用该注解的目的是通知编译器此方法为重写的方法,如果不是重写的方法则编译报错。
②、Deprecated注解:目标没有限制,可以应用于类、方法、成员变量等各种目标。对目标使用该注解的目的是告诉系统此目标已经过时,不建议是用。
③、SuppressWarnings(value={<要关闭的警告类型名称列表>}),例如关闭unchecked、deprecation警告:
@SuppressWarnings(value={"unchecked","deprecation"})
7、利用注解方便开发Web服务
从Java SE 6.0开始,Java SE正式支持用Java来开发Web Services。这将大大方便与Web服务相关的开发与测试,提高开发的效率与速度。下面通过注解创建一个Webservice服务端类。
package com.test.wbs; import javax.jws.WebMethod; import javax.jws.WebService; import javax.jws.soap.SOAPBinding; import javax.xml.ws.Endpoint; /** * * @author js */ @WebService(serviceName="HelloService") @SOAPBinding(style=SOAPBinding.Style.RPC) public class AnnotationWebServie { @WebMethod(operationName = "sayHello") public String serviceMethod(int params1, String params2) { return "我是Java注解式Webservice服务器端:我收到你的参数分别为:params1=" + params1 + ",params2="+params2; } public static void main(String[]args) { Endpoint.publish("http://192.168.0.138:8080/WebServiceExample/AnnotationWebServie", new AnnotationWebServie()); } }
运行上面方法,并通过浏览器访问地址:http://192.168.0.138:8080/WebServiceExample/AnnotationWebServie?WSDL,得到如下结果
对应的客户端,有点麻烦,需要通过jdk的bin下面的wsimport命令来获取服务器的wsdl文件并自动生成客户端的一些辅助类,才能进行开发,此处不详细说明,如需了解请查询相关详细资料。
8、注解与代码自动生成
注解不但能在编译与运行时为系统提供附加的信息,而且可以为专用的工具提供信息来自动生成辅助的代码,大大简化开发的工作(专用工具工作原理:无非也是根据注解信息自动生成代码而已)。
如果需要,开发人员也可以提供自己的代码自动生成功能。从JavaSE5.0开始,系统中提供了一个名称为APT(Annotation Processing Tool)的工具,通过使用此工具开发人员可以方便地开发出自己的代码自动生成功能。
相关推荐
在KUKA机器人的自动化应用中,程序注释是一个至关重要的环节,它有助于理解程序逻辑,提高代码可读性,方便后期的维护和调试。KUKA机器人的编程语言是KUKA Robot Language (KRL),它允许用户通过特定的方式来添加...
在编写复杂的程序时,添加注释是非常重要的实践,它有助于提高代码的可读性,方便后续的维护和调试工作。本文将详细介绍在TIA博途中添加程序注释的几种具体方法。 首先,我们可以为变量添加注释。在PLC变量表中,每...
本文将深入探讨MCS-51单片机的子程序使用及其程序注释的重要性。 在MCS-51单片机编程中,子程序(也称为函数或子例行)是一种组织代码的有效方法,它将常用或复杂的功能封装成独立的模块。这样做的好处包括代码重用...
程序注释工具V1.2.3 1.支持文件和文件夹中.c和.cpp文件函数的提取并可自定义注释内容 2.最大可支持5行函数表达式 3.适用于win7系统,xp,win8未测试 4.一般都适用,非常方便
ABB机器人程序注释 这里以第8套取/放芯及清洗程序为例,即A3100机型,下面作了中文意译注释,只是 个抛砖引玉作用,要做到随便拿一个机型都可以调出来和解决各种问题,还是要靠大家 多关注,多想、多到现场,了解每...
在44BINIT[1].S引导程序注释文档中,我们可以看到每个汇编指令和数据结构都有详细的注解。这些注释提供了对代码功能的清晰解释,对于理解每一部分代码的作用至关重要。例如,注释会解释如何配置特定的寄存器来初始化...
首先,**程序注释**是编程实践中非常重要的一个环节。注释能够帮助开发者和其他读者理解代码的功能、逻辑和工作原理。良好的注释可以提高代码的可读性和可维护性。在心率计项目中,程序注释可能包括对各个函数的解释...
标题中的“自动删除C程序 注解小工具”指的是一个专门设计用于C语言程序的辅助工具,它的主要功能是自动删除代码中的注释部分。在软件开发过程中,注释是用来解释代码逻辑、帮助开发者理解代码用途的重要元素,但在...
这个"38种项目程序带注解 s7200.zip"压缩包文件显然是一个宝贵的资源库,包含了38个不同应用场景的S7-200 PLC程序,并且每个程序都有详细的注释,这对于学习、理解和调试S7-200系统非常有帮助。 首先,S7-200系列是...
在"SPRINGMVC 注解范例程序"中,我们可以深入理解 Spring MVC 如何利用注解进行配置简化,提高开发效率。下面将详细介绍 Spring MVC 中的关键注解和其工作原理。 1. **@Controller**:这是 Spring MVC 中的核心注解...
KUKA机器人程序注解详细解析: 在工业自动化领域,KUKA机器人因其高效、精准的性能而广泛应用。这份文档提供了对KUKA机器人不同程序的详细注解,包括细胞程序(Cell Program)、主程序、焊接程序以及工件处理和维护...
标题中的“169程序注释_simp169行程序注释_measureirq_拓扑优化_优化”指的是一个关于SIMP(Solid Isotropic Material with Penalization)方法的MATLAB程序,该程序涉及到169行代码,并且进行了详细的注释,用于...
该压缩包文件“169程序注释_simp169行程序注释_measureirq_拓扑优化_优化_源码.zip”包含了关于程序注释、中断测量(measureirq)、系统拓扑优化以及代码优化的相关知识。以下是这些主题的详细说明: **程序注释** ...
在处理GX Developer程序时,有时我们会遇到程序注解出现日语乱码的问题,这主要是因为字符编码不匹配导致的。针对这个问题,本文将提供一种有效的解决方案。 首先,我们需要了解乱码产生的原因。在GX Developer中,...
加州理工大学matlab相机标定工具箱,程序注解。注解详细介绍了工具箱的变成原理,对于初学者理解工具箱十分有用
C语言注释删除程序 [程序功能] 1、删除注释,包括块注释(/**/)和行注释(//) 2、删除空白行 3、用指定数量的空格替换TAB字符 [使用方法] 1、在WINDOWS的CMD窗口中键入行命令 2、使用WINDOWS的批处理文件(.BAT...
标题中的“169程序注释_simp169行程序注释_measureirq_拓扑优化_优化.zip”暗示这是一个关于程序优化的项目,其中包含了169行的简化注释,聚焦于“measureirq”功能,且涉及到了拓扑优化。这个压缩包可能是一个编程...
给定 C/C++源程序的源代码,要求去掉所有的注释代码并输出去除注释后的代码。已知 C/C++ 代码的注释有两种:单行注释和多行注释,前者稳以“//”引导的行;后者则是由“/*”和 “*/”包含的部分,可以在同一行内,也...
汇编语言学习资料集锦 汇编语言程序 注释详解 期末复习资料 练习程序 课件 试题答案汇编语言学习资料集锦 汇编语言程序 注释详解 期末复习资料 练习程序 课件 试题答案汇编语言学习资料集锦 汇编语言程序 注释详解 ...