干货系列之java注解
干货系列之java注解
前言
java反射和注解在java里面很重要,但是很多人对这方面的知识理解不是很好,我来说说我自己对java反射和注解的理解,这两块内容本来应该出在一个博客文章里面讲解,但是由于我的java反射说的内容有点小多,然后我就分开将讲解一下。
目录
- 注解的概念
- 注解的类别
- 注解用法
- 通过反射获取注解
- 反射注解一起使用拼写SQL语句实战演练
注解的概念
java注解:
比较官方的说法:
从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。
注解,可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来为 类/方法 注解不同的参数,在用到的地方可以得到不同的 类/方法 中注解的各种参数与值。
说说我的理解
注解就是Annotation,相信不少人也和我之前一样以为和注释一样,是一段辅助性的文字,其实注解不是这样的。注解与注释的区别在于,注解可以实现程序的某些功能。
注解是不会影响java程序的运行,不会干扰程序代码的运行。通俗来讲,注解就像一个标签,初学者需要知道他就像一个功能标签,能实现一些功能就行了!入门了再慢慢深入理解。
看下面的例子你就能更好的理解注解了。
注解的类别
- java语言提供的注解
- 元注解
- 其他注解
java语言提供的注解
1.Override
学过java你就知道,你肯定见过这种
@Override
public Object clone() throws CloneNotSupportedException {}
没错,@Override就是一个java提供的注解。当你要重写父类的方法是需要用到这个注解。
2.@Deprecated
这个注解你能看到的时间比较少,但是你应该见过类似的,编译一个java程序时,编译器可能会提示你你使用了一个过时的方法(idea会),或者过时的类,过时的成员变量。
3.@SuppressWarnings
这个注解的意思是:阻止编译器的警告,上一个注解说到@Deprecated会提示你使用过时方法等的一个警告,当你使用了这个注解之后就不会有这种提示了!这个注解需要一个参数,参数都是提前设计好了的。
参数如下
- deprecation 使用了过时的类或方法的警告
- unchecked 执行了未检查的转换时的警告,如使用集合时未指定泛型
- fallthrough :当在switch语句使用时发生case穿透
- path 在类路径,源文件路径等中有不存在路径的警告
- serial 当在可序列化的类上缺少serialVersionUID定义时的警告
- finally 任何finally子句不能完成时的警告
- all 关于以上所有情况的警告
元注解
所谓元注解就是注解的注解,虽然说这些注解也是java语言提供的,但是他不同于上面说的哪几种注解,上面的几种注解也是由元注解组成的。他们的源代码里面包含了元注解。
元注解有哪些呢?
- @Target:注解的作用目标
- @Retention:注解的生命周期
- @Documented:注解是否应当被包含在 JavaDoc 文档中
- @Inherited:是否允许子类继承该注解
这4个值java8之前的元注解,在java8又新增了一个
@Repeatable 元注解,表示被修饰的注解可以用在同一个声明式或者类型加上多个相同的注解(包含不同的属性值)
我们详细说一下这些注解都是什么意思
1.@Target 注解的作用目标
具体的作用目标有以下几个
- ElementType.TYPE:允许被修饰的注解作用在类、接口和枚举上
- ElementType.FIELD:允许作用在属性字段上
- ElementType.METHOD:允许作用在方法上
- ElementType.PARAMETER:允许作用在方法参数上
- ElementType.CONSTRUCTOR:允许作用在构造器上
- ElementType.LOCAL_VARIABLE:允许作用在局部变量上
- ElementType.ANNOTATION_TYPE:允许作用在注解上
- ElementType.PACKAGE:允许作用在包上
以上都是这个注解的参数
可能有人会问作用目标是什么?就是说我声明的这个注解可以用在那个地方,比如说@Override,是不是只能用在重写的方法上面。如果你学了springboot的话,里面的很多注解都是可以使用在类上面也可以使用在方法上面。
2.@Retention 注解的生命周期
什么意思?注解本身是不会影响正常逻辑程序的运行的,然后这个注解的生命周期指的是我声明的这个注解会保留到什么阶段,具体的参数如下:
- RetentionPolicy.SOURCE:当前注解编译期可见,不会写入 class 文件,会被编译器丢弃
- RetentionPolicy.CLASS:类加载阶段丢弃,会写入 class 文件,会被java虚拟机丢弃
- RetentionPolicy.RUNTIME:永久保存,可以反射获取到对应的注解
3.@Documented 注解是否应当被包含在 JavaDoc 文档中
这个倒没有什么好说的,就是标注被修饰这个注解包含在JavaDoc文档中。
4.@Inherited 是否允许子类继承该注解
简单点说,子类继承父类时,如果父类的注解有@Inherited标识的注解,子类继承过来的时候也会自动继承@Inherited标识的注解。
但是在接口继承的时候,子类不会继承任何@Inherited标识的注解。
5.@Repeatable
在需要对同一种注解多次使用时,往往需要借助@Repeatable。比如说,现在有一篇文章,这篇文章需要添加多个标签,这些标签就相当于注解,但是这个标签只是内容不同,这时候就需要使用到这个注解了。
其他注解
所谓的其他注解就是第三方注解,比如说很火的springboot,它提供了很多的注解,可以替代一些配置文件,告诉这个框架有这个注解是需要提供哪些功能。比如说@Controller,@RequestMapping,@Service等。
注解用法
讲了半天,可能你还是一脸懵逼,你只讲概念,怎么用?
下面就来介绍这个注解怎么用,主要是讲解注解的声明用法。
1.注解声明
public @interface Entity {
}
这个和声明接口很类似,只是在前面多了一个@
具体怎么用,我们用一个例子来讲解
@Target(ElementType.TYPE)//允许声明的注解修饰在接口,类,枚举上面
@Retention(RetentionPolicy.RUNTIME)//代码运行期间一直保存注解,可以通过反射获取
public @interface Entity {
//表名,注解的参数,默认为空
public String tableName() default "";
//中文名称
public String cnName() default "";
}
解释一下注解的参数声明
第一个参数定义参数为String类型,设置default 默认值,表示这个不是必须的,在使用注解的时候没有填写这个参数不会报错,他会使用默认值。
声明好注解之后,我们将这些注解运用到一个实体类上面。
再来一个声明的作用在属性上面的注解。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
//属性的名称
public String fieldName() default "";
//属性的属性中文名称
public String fieldCnName() default "";
//属性的类型
public String Type() default "String";
}
然后我们将这两个注解运用到实体类Student上面。
@Entity(tableName = "student",cnName = "学生表")
public class Student {
@Column(fieldCnName = "姓名",fieldName ="name")
private String name;
@Column(fieldCnName = "年龄",fieldName = "age",Type = "Integer")
private Integer age;
@Column(fieldCnName = "性别",fieldName = "sex")
private String sex;
}
set,get方法没有贴上来。
具体的用法就是这样了。然后我们说说注解与反射的关系,怎么用反射获取注解。
通过反射获取注解
不会反射的请看上一篇文章,8000字为你讲懂反射,然后再回来看这篇注解的文章。
上代码直接
//获取Class类
Class clazz = Student.class;
//获取类上面的注解
Entity entity = (Entity) clazz.getAnnotation(Entity.class);
System.out.println(entity.cnName()+entity.tableName());
//获取所有该类声明的属性
Field fields[] = clazz.getDeclaredFields();
for (Field field:fields){
//获取对应属性上面的注解
Column column = field.getAnnotation(Column.class);
System.out.println(column.fieldCnName());
}
这个运行结果是
学生表student
姓名
年龄
性别
很简单是不是。懂了吗?懂了的话关注走一波?精彩美文每天为你推送,喜欢手机看文章的还可以(wx search 全栈学习笔记)!
反射注解一起使用拼写SQL语句实战演练
其实这一部分你懂反射和注解就会了,通过反射和注解你可以实现一个简单的万能的增删改查。贴个新增的SQL语句代码吧!
//insert into student_test(student_id,student_name,student_sex) values (1,"Jack","男")
StringBuilder sql = new StringBuilder();
Class clazz = object.getClass();
sql.append("insert into ");
//获取类上面的注解
Entity entity = (Entity) clazz.getAnnotation(Entity.class);
sql.append(entity.tableName());
sql.append("(");
Field[] fields = clazz.getDeclaredFields();
for(Field field:fields){
sql.append(field.getAnnotation(Column.class).fieldName()).append(",");
}
sql.deleteCharAt(sql.length()-1);
sql.append(")");
sql.append(" values (");
for(Field field:fields){
field.setAccessible(true);
Object value = field.get(object);
if(value.getClass().equals(String.class)){
sql.append("\"").append(value).append("\"").append(",");
}else {
sql.append(value).append(",");
}
}
sql.deleteCharAt(sql.length()-1);
sql.append(")");
System.out.println(sql.toString());
return sql.toString();
结语:觉得文章不错的,带上原文链接,欢迎转发,如果你发现文章中有错误可以评论或者私信我,及时修改!(wx search 全栈学习笔记)精彩美文每天为你推送!