注解:
注解是元数据的一种形式,它提供了关于程序代码的额外信息。注解通常以特殊的注释语法编写,它们可以被附加到类、方法、字段等程序元素上,用于提供关于这些元素的额外信息或指令。
注解的作用:提供元数据信息:注解可以用于提供关于程序元素(如类、方法、变量)的元数据信息,这些信息可以在编译时、运行时或工具处理时使用。配置和控制:注解可以用于配置和控制程序的行为。通过在类或方法上添加特定的注解,可以告诉编译器或运行时环境执行特定的操作。代码生成:某些注解可以用于生成额外的代码或配置文件。
元注解:
元注解是一种注解的注解,它用于描述其他注解。
@Retention: 只能用于修饰一个 Annotation 定义, 用于指定该 Annotation 可以保留多长时间,@Rentention 包含一个 RetentionPolicy 类型的成员变量, 使用 @Rentention 时必须为该 value 成员变量指定值(值有三种)。
(1)RetentionPolicy.SOURCE: 编译器使用后,直接丢弃这种策略的注释。
(2)RetentionPolicy.CLASS: 编译器将把注解记录在 class 文件中 . 当运行 Java 程序时 , JVM 不会保留注解。这是默认值。
(3)RetentionPolicy.RUNTIME: 编译器将把注解记录在 class 文件中 . 当运行 Java 程序时 , JVM 会保留注解。程序可以通过反射获取该注解。
@Target:用于修饰 Annotation 定义,指定被修饰的 Annotation 能用于修饰哪些程序元素。
用于描述注解的使用范围,也就是注解可以用在什么地方,取值有:
CONSTRUCTOR:用于描述构造器。
FIELD:用于描述字段。
LOCAL_VARIABLE:用于描述局部变量。
METHOD:用于描述方法。
PACKAGE:用于描述包。
PARAMETER:用于描述参数。
TYPE:用于描述类,包括class,interface,enum。
。
@Inherited:使被它修饰的注解具有继承性(如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解)。。
@Documented
将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。它是一个标记注解,没有成员。
定义注解
图片来源:注解和反射-KuangStudy-文章
//自定义注解
public class Demo03_CustomAnnotation {
//注解可以显示赋值,如果没有默认值,就必须给注解赋值
@MyAnnotation2(name = "张三")
public void test() {
}
}
@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2 {
//注解的参数:参数类型+参数名()
//String name();
String name() default "";
int age() default 0;
int id() default -1;//-1代表不存在
String[] schools() default {"牛津大学","哈佛大学"};
定义新的注解类型使用@interface关键字(在原有的interface关键字前增加@符号)
//定义一个简单的注解类型
public @interface 注解名
{ 成员变量;
}
注解可以带成员变量,或者没有成员变量。
下面定义了一个无成员变量的名为Test的简单注解:
public @interface Test
{
}
成员变量在注解定义中以无形参的方法形式来声明,其方法名和返回值定义了该成员变量的名字和类型。
如下代码定义带两个成员变量的名为MyTag的注解:
public @interface MyTag
{
String name(); //注解中的成员变量以方法的形式来定义
int age();
}
定义了注解后,可用注解来修饰程序中的类、方法、变量、接口等定义。
使用注解的语法是:@注解名,
通常会把注解放在所有修饰符之前,单独成行;
例如,使用上面定义的无成员变量的简单注解 @Test修饰类定义
@Test
public class MyClass
{
...
}
如下程序使用简单注解@Test来修饰方法。
public class MyClass
{ @Test
public void info()
}
如果注解是带成员变量的注解,那么,
使用该注解时就应该为它的成员变量指定值,
因而注解的长度可能较长,所以通常把注解另放一行,
如下面程序所示,使用上面定义的带成员变量的@MyTag注解,需要为成员变量赋值:
public class Test
{
@MyTag(name ="xx",age = 6)
public void info()
{...}
...
}
也可以在定义注解的成员变量时为其指定初始值(默认值),
指定成员变量的初始值可使用default关键字。
如下代码定义了@MyTag注解,该注解里包含了两个成员变量:name和age,
这两个成员变量使用default指定了初始值。
public @interface MyTag
{
String name() default "yeeku";
int age() default 32;
}
如果为注解的成员变量指定了默认值,
使用该注解时则可以不为这些成员变量指定值,而是直接使用默认值。
public class Test
{
@MyTag //因为它的成员变量有默认值,所以可以不为它的成员变量指定值
public void info()
{ ... }
}
当然也可以在使用MyTag注解时为成员变量指定值,
如果为MyTag的成员变量指定了值,则默认值不会起作用。
根据注解是否可以包含成员变量,可以把注解分为如下两类:
标记注解:没有定义成员变量的注解类型被称为标记。
这种注解仅利用自身的存在与否来提供信息,如前面介绍的@Override、@Test等注解。
本次学习任务:自己设计一个注解接口,并写出接口处理程序,并进行测试
package Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(value = RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@interface annotation {
String value() default "Hello World";
}
package Annotation;
import java.lang.reflect.Method;
public class annotationProcessor {
public static void processAnnotations(Object object) {
Class<?> testClass = object.getClass();
// 遍历testClass对应的类里的所有方法
for (Method method : testClass.getDeclaredMethods()) {
//如果该方法使用了@annotation修饰
if (method.isAnnotationPresent(annotation.class)) {
//获取该方法上的@annotation注解
annotation annotation = method.getAnnotation(annotation.class);
//获取注解里的value值
String value = annotation.value();
System.out.println("Method " + method.getName() + " has @annotation with value: " + value);
}
}
}
}
package Annotation;
public class Test {
@annotation
public void method_A(){
}
@annotation("Hello Sky")
public void method_B(){
}
@annotation("Hello Earth")
public void method_C(){
}
}
package Annotation;
public class Main {
public static void main(String[] args) {
Test test = new Test();
annotationProcessor.processAnnotations(test);
}
}