Java自定义注解
如想了解更多更全面的Java必备内容可以阅读:所有JAVA必备知识点面试题文章目录:
一、自定义注解
1、什么是注解?
Jdk1.5新增新技术,注解。很多框架为了简化代码,都会提供有些注解。可以理解为插件,是代码级别的插件,在类的方法上写:@XXX,就是在代码上插入了一个插件。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
注解分类:
- 元注解: 元注解是用于定义注解的注解,包括@Retention、@Target、@Inherited、@Documented、@Repeatable (JDK1.8加入)五种。
- JDK自带的标准注解: 包括@Override、@Deprecated、@SuppressWarnings等,使用这些注解后编译器就会进行检查。
- 自定义注解: 用户可以根据自己的需求定义注解。
2、Java注解的架构?
- 注解是接口类,都继承自Annotation接口类
- 1 个 Annotation 和 1 个 RetentionPolicy 关联,可以理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性;
- 1 个 Annotation 和 1~n 个 ElementType 关联,可以理解为:对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性;
- Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override 等等。 Annotation 的每一个实现类都和1个 RetentionPolicy 关联并且和 1~n 个 ElementType 关联。
3、注解的作用?
注解的用途有很多,总起起来,注解有如下四大部分作用:
- 生成文档,通过代码里标识的元数据生成javadoc文档。
- 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
4、对元注解的了解有多少?
-
@Retention : Retention(有保留、保持)的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期。
- @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中(编译期),在class字节码文件中不包含。
- @Retention(RetentionPolicy.CLASS), 注解会在class字节码文件中存在(类加载),但运行时无法获得。
- @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在(JVM中运行),在运行时可以通过反射获取到。
- 如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME) 。
-
@Target: Target的英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型。
- @Target(ElementType.TYPE) 作用接口、类、枚举、注解
- @Target(ElementType.FIELD) 作用属性字段、枚举的常量
- @Target(ElementType.METHOD) 作用方法
- @Target(ElementType.PARAMETER) 作用方法参数
- @Target(ElementType.CONSTRUCTOR) 作用构造函数
- @Target(ElementType.LOCAL_VARIABLE)作用局部变量
- @Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
- @Target(ElementType.PACKAGE) 作用于包
- @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
- @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
-
@Documented: Document的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
-
@Inherited: Inherited的英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。
/**自定义注解*/ @Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface MyTestAnnotation { } /**父类标注自定义注解*/ @MyTestAnnotation public class Father { } /**子类*/ public class Son extends Father { } /**测试子类获取父类自定义注解*/ public class test { public static void main(String[] args){ //获取Son的class对象 Class<Son> sonClass = Son.class; // 获取Son类上的注解MyTestAnnotation可以执行成功 MyTestAnnotation annotation = sonClass.getAnnotation(MyTestAnnotation.class); } }
-
@Repeatable: Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。
/**玩家注解*/ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface People { Game[] value() ; } /**游戏注解*/ @Repeatable(People.class) @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Game { String value() default ""; } /**作用一个对象多次,每次作用注解又可以代表不同的含义*/ @Game(value = "LOL") @Game(value = "PUBG") @Game(value = "NFS") @Game(value = "Dirt4") public class PlayGame { }
5、注解的本质是什么?
注解的本质就是一个Annotation接口。 注解本身就是Annotation接口的子接口,也就是说注解中其实是可以有属性和方法,但是接口中的属性都是static final的,对于注解来说没什么意义,而我们定义接口的方法就相当于注解的属性,也就对应了前面说的为什么注解只有属性成员变量,其实他就是接口的方法,这就是为什么成员变量会有括号,不同于接口我们可以在注解的括号中给成员变量赋值。
/**Annotation接口 JDK1.7源码*/
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
6、通过自定义注解 实现ORM框架映射简单案例,理解为上,重在思路。
自定义表映射注解:
/**
* @classDesc: 自定义表映射注解
* @author: 精彩猿笔记
* @createTime: 2020年7月28日16:27:07
* @version: v1.0
*/
@Target(value = { ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface SetTable {
//对应数据库表名称
String value();
}
自定义字段属性:
/**
* @classDesc: 自定义表映射注解
* @author: 精彩猿笔记
* @createTime: 2020年7月28日16:27:07
* @version: v1.0
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface SetProperty {
//字段名称
String name();
//长度
int leng();
}
实体类代码实现:
@SetTable(value = "student_info")
class User {
@SetProperty(value = "student_id", leng = 10)
private String id;
@SetProperty(value = "student_name", leng = 25)
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试类代码实现:
public class Test002 {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> forName = Class.forName("com.entity.User");
StringBuffer sf = new StringBuffer();
sf.append(" select ");
// 获取当前的所有的属性
Field[] declaredFields = forName.getDeclaredFields();
for (int i = 0; i < declaredFields.length; i++) {
Field field = declaredFields[i];
ProPerty proPertyAnnota = field.getDeclaredAnnotation(SetProperty.class);
String proPertyName = proPertyAnnota.value();
sf.append(" " + proPertyName);
if (i < declaredFields.length - 1) {
sf.append(" , ");
}
}
Table tableAnnota = forName.getDeclaredAnnotation(SetTable.class);
// 表的名称
String tableName = tableAnnota.value();
sf.append(" from ").append(tableName).append(";");
System.out.println(sf.toString());
}
}
输出结果:
select student_id, student_name from student_info;
====================================================================
······
帮助他人,快乐自己,最后,感谢您的阅读!
所以如有纰漏或者建议,还请读者朋友们在评论区不吝指出!
个人网站…知识是一种宝贵的资源和财富,益发掘,更益分享…