文章目录
- 前言
- 一、概念
- 二、使用实例
- 1、Junit测试中
- 2、JDK内置注解
- 三、自定义注解
- 1、注解声明
- 2、注解配置参数
- 2.1 配置参数的类型:
- 2.2 注意
- 2.3 两个概念
- 3、使用注解
- 四、元注解
- 1、@Retention
- 1.1 RetentionPolicy.SOURCE
- 1.2 RetentionPolicy.CLASS
- 1.3 RetentionPolicy.RUNTIME
- 1.4 总结
- 2、@Target
- 3、@Documented
- 4、@Inherited
- 4.1 自定义注解、接口、实现类
- 4.2 测试
前言
📢 大家好,我是程序员Forlan,本篇内容主要分享注解,属于基础内容,通过概念入手,了解使用的场景,自定义注解,理解清楚注解的具体用法~
一、概念
注解(Annotation),也叫元数据,是JDK5.0 新增的
注解其实就是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。
通过使用注解,程序员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充信息。使用注解时要在其前面增加@符号,并把该注解当成一个修饰符使用。用于修饰它支持的程序元素。
重要性?
Annotation 可以像修饰符一样被使用,可用于修饰包,类,构造器,方法,成员变量,参数,局部变量的声明,这些信息被保存在Annotation的"name=value"对中。在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/ArIdroid中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替JavaEE旧版中所遗留的繁冗代码和XML配置等。未来的开发模式都是基于注解的,JPA(java的持久化API)是基于注解的,Spring2.5以前都是基于注解的,Hibernate3.x以后也是基于注解的,现在的Struts2有一部分也是基于注解的了,注解是一种趋势,一定程度上可以说 :框架=注解+反射+设计模式。
二、使用实例
1、Junit测试中
public class AnnotationTest {
@Before
public void start() {
System.out.println("方法开始了。。。");
}
@After
public void end() {
System.out.println("方法结束了。。。");
}
@Test
public void testForlan() {
System.out.println("执行方法");
}
}
2、JDK内置注解
@Override:限定于重写父类方法,该注解只能用于方法,重写错误,就会有提示
@Deprecated:用于表示所修饰的元素(类,方法,构造器,属性等)已过时,通常是因为所修饰的结构危险或存在更好的选择
@SuppressWarnings:抑制编译器警告
三、自定义注解
public @interface Forlan {
public String name();
int age default 18;
}
1、注解声明
声明使用的是关键字@interface,这个就是注解,在底层实现上,所有定义的注解都会自动继承java.lang.annotation.Annotation接口
2、注解配置参数
2.1 配置参数的类型:
- 基本数据类型
- String
- Class
- 枚举
- 注解
- 数组
2.2 注意
- 如果只有一个参数的话,名字尽量叫value,因为可以省略不写
- 如果设置了默认值,那么无需赋值,default代表默认值
- 如果没有默认值,后续使用是必须赋值的
- 访问修饰符必须为public,不写默认是public
- ()只是一个特殊语法,不能在其中定义任何东西
- 注解的内部是可以不定义属性的
2.3 两个概念
标记:内部没有配置参数的注解
元数据:内部有配置参数的注解
3、使用注解
直接写@注解名,比如@Forlan
四、元注解
元注解是用于修饰其它注解的注解
JDK5.0提供了四种元注解:Retention, Target, Documented, Inherited
1、@Retention
用于修饰注解,指定注解的生命周期,使用@Rentention时必须为该value成员变量指定值
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
1.1 RetentionPolicy.SOURCE
在源文件中有效,编译器会直接丢弃这种策略的注释,即在.class文件中不会保留注解信息
下面我们通过反编译查看字节码文件,发现字节码文件中没有@Forlan这个注解,也就是使用这个注解的地方看不到,不起作用
1.2 RetentionPolicy.CLASS
默认状态,在class文件中有效,保留在.class文件中,但是当运行Java程序时,他就不会继续加载了,不会保留在内存中,JVM不会保留注解
反编译查看字节码文件,字节码文件中带有@Forlan
1.3 RetentionPolicy.RUNTIME
在运行时有效,当运行 Java程序时,JVM会保留注释,加载到内存中了,那么程序可以通过反射获取该注释
1.4 总结
一般使用RUNTIME,SOURCE和CLASS一般不使用,默认是CLASS
2、@Target
用于修饰注解的注解,指定作用目标,使用@Target时必须为该value成员变量指定值
包含很多种类型,如下:
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/** Type parameter declaration */
TYPE_PARAMETER,
/** Use of a type */
TYPE_USE
}
3、@Documented
一般很少使用
被该元注解修饰的注解,将被javadoc工具提取成文档。默认情况下,Javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了
4、@Inherited
一般极少使用
被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰了,则其子类将自动具有该注解
只是继承,实现接口是没有的
4.1 自定义注解、接口、实现类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface Forlan {
}
@Forlan
public class Food {
...
}
@MyAnnotation
public class Rice extends Food {
...
}
4.2 测试
可以看到,打印出来两个注解,@Forlan就是继承父类的
Class cls = Class.forName("cn.forlan.reflection.entity.Dog");
Annotation[] annotations = cls.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
@cn.forlan.annotation.Forlan()
@cn.forlan.reflection.MyAnnotation()