java注解的实现以及注解的作用
- 四大元注解
- 自定义注解
- java反射
- java注解在java框架中的使用
四大元注解
java注解是在jdk1.5版本出现的,注解(Annotation)可以理解为对代码的解释,可以做一些扩展或者补充。注解通常有这样几个作用范围、作用在class上、还有就是方法上method,还有就是字段上,还可以再注解上。注解与注释的不同就不用赘述了。可能我们在最开始学习或者入门做些小的开发时,很少去理解注解到底是怎么实现。但是只有当我们能真正理解注解,并能在实际中使用他。自己设计出非常精妙的注解,使我们的代码结构更加优雅,功能更加强大的时候,我想这是非常享受。尽管我也是初学者,但是我也很想享受代码在我指尖跳跃的感觉(哈哈哈哈哈哈哈哈哈)。以下都是我的浅见,只为每天坚持学习。
在学习注解之前,我认为应该有一定的java反射的知识,还有jvm的知识。这样我们理解起来就会更加深刻。
首先我们看一下什么是元注解,元注解表示的是对注解的注解,也就是我们在自定义注解的时候,通常都要使用到这些元注解,只有掌握好元注解,才能设计好自定注解。
注解名 | 作用 |
---|---|
@Target | 通常用于表示该注解作用的范围,有一个枚举类型表示ElementType |
@Retention | 我理解该注解的生命周期,通过一个RetentionPolicy的枚举类型来表示注解存在的时间 |
@Documented | 描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。 |
@Inherited | 使被它修饰的注解具有继承性 |
以上就是四大元注解,其中上述提到的枚举类型,可以展示一下他们到底枚举的什么内容。
ElementType
类型 | 解释 |
---|---|
TYPE | 通常就用来表示该注解作用在类上 |
FIELD | 作用在字段上 |
METHOD | 作用在方法上 |
PARAMETER | 形式参数声明 |
CONSTRUCTOR | 构造函数声明 |
LOCAL_VARIABLE | 局部变量声明 |
ANNOTATION_TYPE | 注解上 |
PACKAGE | 包上 |
TYPE_PARAMETER | |
TYPE_USE |
常用的就Type、FIELD、METHOD
RetentionPolicy
枚举名 | 作用 |
---|---|
SOURCE | 编译层面 |
CLASS | 注释将由编译器记录在类文件中但不需要在运行时被VM保留。这是默认值行为。 |
RUNTIME | 可以通过反射获取 |
自定义注解
自定义一个注解非常简单,1、@interface +注解名定义一个注解。2、在自定义的注解上使用元注解。3、注解内的元素类型,只能是public,并且只能是基本的数据类型(int,float…),以及String Class enum,Annotation,和以上数据类型的数组。4、可以指定默认值。但是在非基本类型数据在指定默认值时,都不能使用null作为默认值。例如,创建一个用于配置信息的注解。
public class AppConfig {
@Config("123")
private String appId;
@Config("456")
private String appSecret;
private String Key;
public AppConfig()
{
System.out.println("appconfig...");
}
public String getKey() {
return Key;
}
public void setKey(String key) {
Key = key;
}
public String getAppId() {
return appId;
}
public void setAppId(String appId) {
this.appId = appId;
}
public String getAppSecret() {
return appSecret;
}
public void setAppSecret(String appSecret) {
this.appSecret = appSecret;
}
@Param(clazz = Person.class,id = 1)
public void doPost(){
}
@Override
public String toString() {
return "AppConfig{" +
"appId='" + appId + '\'' +
", appSecret='" + appSecret + '\'' +
", Key='" + Key + '\'' +
'}';
}
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Param {
Class<?> clazz();
int id();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeTest {
boolean flag() default true;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Config {
public String value() default "";
}
public class AppConfigService {
public static void main(String[] args) {
AppConfig appConfig = initAppConfig();
System.out.println("通过初始化的值:"+appConfig.toString());
}
public static AppConfig initAppConfig(){
try{
Class clazz = Class.forName("cn.hbmy.AppConfig");
AppConfig appConfig = (AppConfig) clazz.newInstance();
/**
* 对于private 属性通过getDeclaredFields方法可以获取到
* */
Field[] fields = clazz.getDeclaredFields();
for(Field field:fields){
System.out.println("获取class中的字段"+field);
}
/**
*获取类上的注解
* */
TypeTest typeTest =(TypeTest) clazz.getAnnotation(TypeTest.class);
System.out.println("获取类上注解值:"+typeTest.flag());
/**
* 获取方法
* */
Method[] methods = clazz.getDeclaredMethods();
for(Method method:methods)
{
if(method.isAnnotationPresent(Param.class)){
//判断这个方法是否包含Param注解
method.setAccessible(true);
Param param = (Param) method.getAnnotation(Param.class);//得到方法上的注解
Method[] methods1 = param.annotationType().getDeclaredMethods();
for(Method me:methods1){
System.out.println("注解值:"+me.invoke(param, null));
}
System.out.println("获取class中的方法"+method.getName()+" "+method.getParameters());
}
}
/**
* 获取构造函数,获取私有的通过getDeclaredConstructors方法
* */
Constructor<AppConfig> [] constructors = clazz.getConstructors();
for(Constructor constructor:constructors)
{
System.out.println("构造函数"+constructor);
}
/**
* 获取注解
* */
for(Field field:fields){
if(!field.isAccessible()){
field.setAccessible(true);
}
Config config = field.getAnnotation(Config.class);
if(config!=null)
{
field.set(appConfig,config.value());//设置注解值
System.out.println("config.value:"+field.getName()+" "+config.value());
}
}
return appConfig;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
}
通过上述的例子可以总结自定注解主要包括两步,1、定义一个注解。2、编写注解解析器。如果注解没有解析恐怕注解将毫无作用。
上述例子可能不能很好地体现出注解的作用,现在假设你希望提供一些对象映射的功能,能够自动生成数据库表。用以存储javaBean对象。如果使用xml的话,需要指明类名,以及字段的相关信息。然而如果使用注解的话,我们只需将相关信息保存在javaBean中。为此我们需要定义一些新注解,用以定义与bean关联的表名,以及与bean属性相关连的列的名字和数据类型。
定义表名注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TableDB {
String name();
}
定义两种数据类型
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 0;
String name() default "";
Constraints constraints() default @Constraints;//默认初始
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface SQLInteger {
String name() default "";
Constraints constraints() default @Constraints;
}
定义约束
public @interface Constraints {
boolean primary_key()default false;
boolean unique() default false;
boolean allow_null() default true;
}
定义Bean
@TableDB(name = "Member_T")
public class Member {
@SQLInteger(constraints = @Constraints(primary_key = true))
public int id;//主键
@SQLString(20)
public String userName; //姓名
@SQLString(20)
public String passWord; //密码
@SQLInteger
public int age; //年龄
}
注解解析器
public class AnnotationParse {
public static String parseDBAnnotation(){
Class clazz = Member.class;
TableDB tableDb =(TableDB)clazz.getAnnotation(TableDB.class);
StringBuffer res = new StringBuffer();
String name = tableDb.name();
res.append("CREATE TABLE ").append(name).append("(").append("\n");
//
Field[] fields = clazz.getDeclaredFields();
for(Field field:fields){
field.setAccessible(true);
if(field.isAnnotationPresent(SQLInteger.class)){
SQLInteger sqlInteger = field.getAnnotation(SQLInteger.class);
res.append(field.getName()).append(" ").append("INT ").append(getConstraints(sqlInteger.constraints())).append(",");
res.append("\n");
}else if(field.isAnnotationPresent(SQLString.class)){
SQLString sqlString = field.getAnnotation(SQLString.class);
res.append(field.getName()).append(" ").append("VARCHAR(").append(sqlString.value()).append(")");
res.append(getConstraints(sqlString.constraints())).append(",");
res.append("\n");
}
}
res.append(");");
System.out.println(res.toString());
return res.toString();
}
public static String getConstraints(Constraints constraints){
StringBuffer s = new StringBuffer();
if(!constraints.allow_null()){
s.append("NOT NULL");
}
if(constraints.primary_key()){
s.append("PRIMARY KEY");
}
if(constraints.unique()){
s.append("UNIQUE");
}
return s.toString();
}
public static void main(String[] args) throws ClassNotFoundException {
parseDBAnnotation();
}
}
运行效果图,处理一下最后一个,就可以了。
java反射
Java的注解需要依赖于Java的反射机制,Java反射是在运行时可以通过类名.class或者Class.forName等方法获取Class。该Class时类加载过程中加载这一阶段会实现的。
java注解在java框架中的使用
注解在框架中使用有@Autowire、@RequestMapping、@Mapper、@Controller、@Service…等等,还有SpringBoot中的自动装配原理也是通过组合注解实现的,因此注解使得我们需要进行繁琐的操作变得更加简单。用好注解,写好注解,理解注解的底层实现可以让我们更能理解这一特性。不在每天依靠记忆去记住。
更多推荐
Java注解实现以及应用
发布评论