1 注解的定义和作用
注解与注释:
注解:告诉编译器如何运行程序!
注释: 给程序员阅读,对编译、运行没有影响;
注解作用
-
告诉编译器如何运行程序;
-
简化(取代)配置文件
// 重写父类的方法
@Override
public String toString() {
return super.toString();
}
// 抑制编译器警告 List不加泛型会出警告
@SuppressWarnings({"unused","unchecked"})
private void save() {
List list = null;
}
// 标记方法以及过时
@Deprecated
private void save1() {
}
2 自定义注解
通过自定义注解,可以给类、字段、方法上添加描述信息!
2.1 元注解
元注解,表示注解的注解!
- 指定注解的可用范围:
@Target({
TYPE, 类
FIELD, 字段
METHOD, 方法
PARAMETER, 参数
CONSTRUCTOR, 构造器
LOCAL_VARIABLE 局部变量
})
- 指定注解的生命周期
@Retention(RetentionPolicy.SOURCE) 注解只在源码级别有效
@Retention(RetentionPolicy.CLASS) 注解在字节码级别有效 默认值
@Retention(RetentionPolicy.RUNTIME) 注解在运行时期有效
2.2 案例
//表示这个注解可以作用到方法、属性、类上
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String name() default "";
//带默认值的属性,使用时候不给这个属性赋值,也有一个默认值
int age() default 20;
//如果使用注解里面的value属性,使用的时候可以省略.
//前提是:注解中只有这一个属性时候
String[] value() default {};
}
//@Author("男")
//@Author(value = "男")
//@Author(value = {"男", "女"})
@Author(name = "zhao", age = 12, value = "男")
public class AuthorDemo {
@Author
private String str;
@Author(name = "zhangsan", age = 23, value = {"男", "女"})
//@Author(name = "zhangsan")
public void add() {
}
@Test
public void test1() throws NoSuchMethodException {
Class<AuthorDemo> clazz = AuthorDemo.class;
Author typeAuthor = clazz.getAnnotation(Author.class);
System.out.println(typeAuthor.value()[0]);
//1.先获得代表这个方法的Method
Method method = clazz.getDeclaredMethod("add");
//2.在Method上拿到指定注解
Author methodAnnotation = method.getAnnotation(Author.class);
System.out.println(methodAnnotation.name());//zhangsan
System.out.println(methodAnnotation.age());//23
System.out.println(Arrays.toString(methodAnnotation.value()));//[男, 女]
}
}
3 解释一下
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String[] value() default {};
}
这是一个 Java 注解的定义。注解是 Java 中的一种元数据,可以附加到代码中的类、方法、字段等元素上,用于提供额外的信息。让我们详细解释这个注解的各个部分。
注解定义
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String[] value() default {};
}
详细解释
-
@Target
注解(元注解):@Target
注解指定了这个自定义注解可以应用的目标。- 在这里,
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
表示这个注解可以应用于方法、字段和类(类型)。 ElementType
的常见类型包括:ElementType.METHOD
:方法ElementType.FIELD
:字段ElementType.TYPE
:类、接口(包括注解类型)或枚举声明
-
@Retention
注解(元注解):@Retention
注解指定了这个自定义注解的保留策略。- 在这里,
@Retention(RetentionPolicy.RUNTIME)
表示这个注解在运行时可见。这意味着可以使用反射机制在运行时读取这个注解。 RetentionPolicy
的常见类型包括:RetentionPolicy.SOURCE
:注解只在源码中存在,编译时会被丢弃。RetentionPolicy.CLASS
:注解在编译时会被保留在类文件中,但在运行时不会被保留。RetentionPolicy.RUNTIME
:注解在运行时保留,可以通过反射机制读取。
-
注解的定义:
public @interface Author
:这是定义一个名为Author
的注解。String[] value() default {};
:定义了一个名为value
的属性,它是一个String
数组,默认值是一个空数组。- 在使用这个注解时,可以提供一个或多个字符串值。例如:
@Author({"Alice", "Bob"})
或@Author("Alice")
。
- 在使用这个注解时,可以提供一个或多个字符串值。例如:
示例使用
应用在类上
@Author("Alice")
public class MyClass {
// 类代码
}
应用在方法上
public class MyClass {
@Author({"Alice", "Bob"})
public void myMethod() {
// 方法代码
}
}
应用在字段上
public class MyClass {
@Author("Charlie")
private String myField;
}
读取注解
//如果指定类型的注解存在于此元素上,方法返回true,否则返回false。
A.isAnnotationPresent(B.class)
//B类型的注解是否存在于A元素(可以是类、字段(属性)、方法)上
通过反射可以读取这些注解的信息。例如:
import java.lang.reflect.Method;
public class AnnotationReader {
public static void main(String[] args) throws Exception {
// 获取类上的注解
Class<MyClass> clazz = MyClass.class;
if (clazz.isAnnotationPresent(Author.class)) {
Author author = clazz.getAnnotation(Author.class);
System.out.println("Class Author: " + String.join(", ", author.value()));
}
// 获取方法上的注解
Method method = clazz.getMethod("myMethod");
if (method.isAnnotationPresent(Author.class)) {
Author author = method.getAnnotation(Author.class);
System.out.println("Method Author: " + String.join(", ", author.value()));
}
// 获取字段上的注解
Field field = clazz.getDeclaredField("myField");
if (field.isAnnotationPresent(Author.class)) {
Author author = field.getAnnotation(Author.class);
System.out.println("Field Author: " + String.join(", ", author.value()));
}
}
}
总结
这个注解定义了一个名为 Author
的自定义注解,可以应用于类、方法和字段。通过 @Target
注解指定了可以应用的目标,通过 @Retention
注解指定了它的保留策略为运行时,并定义了一个 String
数组类型的 value
属性。这个注解可以在源码中提供作者信息,并在运行时通过反射机制读取。
4 如果使用时只用@Author会发生什么
如果在使用 @Author
注解时只写 @Author
而不提供任何参数,根据注解的定义,注解的 value
属性将使用默认值。因为 value
属性的默认值是一个空数组 default {}
,所以这相当于没有指定任何作者信息。
注解的默认值
在注解的定义中,String[] value() default {};
表示 value
属性有一个默认值,即一个空的 String
数组。如果使用注解时不提供任何参数,value
属性将使用这个默认值。
示例使用
仅使用 @Author
注解
@Author
public class MyClass {
// 类代码
}
使用反射读取注解
通过反射读取注解时,如果没有提供任何参数,value
属性将是一个空数组。
import java.lang.reflect.Method;
public class AnnotationReader {
public static void main(String[] args) throws Exception {
// 获取类上的注解
Class<MyClass> clazz = MyClass.class;
if (clazz.isAnnotationPresent(Author.class)) {
Author author = clazz.getAnnotation(Author.class);
System.out.println("Class Author: " + String.join(", ", author.value()));
}
// 获取方法上的注解
Method method = clazz.getMethod("myMethod");
if (method.isAnnotationPresent(Author.class)) {
Author author = method.getAnnotation(Author.class);
System.out.println("Method Author: " + String.join(", ", author.value()));
}
// 获取字段上的注解
Field field = clazz.getDeclaredField("myField");
if (field.isAnnotationPresent(Author.class)) {
Author author = field.getAnnotation(Author.class);
System.out.println("Field Author: " + String.join(", ", author.value()));
}
}
}
输出结果
如果 @Author
注解没有提供任何参数,读取到的 value
属性将是一个空数组,因此输出将为空。
示例类
@Author
public class MyClass {
@Author
private String myField;
@Author
public void myMethod() {
// 方法代码
}
}
示例输出
Class Author:
Method Author:
Field Author:
总结
当你使用 @Author
注解而不提供任何参数时,注解的 value
属性将使用其默认值(即一个空数组)。读取这个注解时,会发现 value
属性是空的,表示没有指定任何作者信息。这是因为 String[] value() default {}
定义了 value
属性的默认值为一个空数组。
5 不提供参数的注解有啥用?
注解在 Java 中的作用取决于它们如何被设计和使用。虽然在某些情况下,不提供参数的注解(例如 @Author
没有参数)可能看起来没有明显的用途,但它们仍然可以在特定的上下文中有意义。以下是一些可能的用途和设计意图:
1. 标记用途
不带参数的注解可以用作简单的标记,用来标记某些元素(类、方法、字段等)具有特定的特性或需要特定的处理。
示例
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Important {
// 这个注解没有参数,仅用于标记
}
在使用时:
@Important
public class MyClass {
@Important
private String importantField;
@Important
public void importantMethod() {
// 重要的方法
}
}
2. 反射处理
在运行时,通过反射来检查和处理这些标记注解。例如,可以在框架或库中使用这些注解来执行特定的逻辑。
示例:反射处理标记注解
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class AnnotationProcessor {
public static void main(String[] args) throws Exception {
Class<MyClass> clazz = MyClass.class;
if (clazz.isAnnotationPresent(Important.class)) {
System.out.println("Class " + clazz.getName() + " is important.");
}
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(Important.class)) {
System.out.println("Field " + field.getName() + " is important.");
}
}
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Important.class)) {
System.out.println("Method " + method.getName() + " is important.");
}
}
}
}
3. 兼容性和扩展性
设计注解时允许有参数和无参数两种形式,可以增强注解的灵活性和兼容性。在需要详细信息时可以传递参数,而在不需要详细信息时可以仅使用标记。
示例
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
String[] value() default {};
}
// 使用时可以只作为标记
@Author
public class MyClass {
// 或者提供具体的值
@Author({"Alice", "Bob"})
private String importantField;
@Author("Charlie")
public void importantMethod() {
// 重要的方法
}
}
4. 默认值的意义
即使是默认值为空,注解仍可以提供关于代码结构的信息,并且允许将来扩展。例如,可以在后续开发中引入新的处理逻辑或使用策略,而不需要修改现有的代码。
总结
虽然不带参数的 @Author
注解在看起来可能没有直接的作用,但它仍可以用于标记、反射处理、提供兼容性和扩展性等用途。实际的用处取决于开发者如何设计和使用这些注解。在实际开发中,注解的使用往往是为了提供元数据,标记特定特性,并在运行时进行处理或执行特定的逻辑。