Java注解(Annotation
)是ava语言中非常重要的一个特性。它是用于为程序元素(类、方法、变量等)添加元数据的一种机制,本质上是一种接口,定义了一组可选属性和默认值,可以表示程序中的元数据信息。通过使用注解,开发者可以为代码添加各种信息和功能,例如标记废弃的方法或类、进行安全检查、提供配置文件读取、记录日志信息等。
注解是非常灵活和强大的特性,它可以帮助程序员更好地组织和管理代码,提高开发效率和代码质量,实现了更高效、更智能的编程方式
Java注解是一种通过在程序中添加元数据的方式来为代码添加额外信息和标记的机制。Java注解本质上是一种接口(只不过它的接口名前面加了一个@符号),定义了注解的元素和属性,可以包含基本数据类型、枚举类型、Class类型、注解类型以及数组等元素,并可以有默认值。
Java注解的实现原理主要基于Java**反射机制
**,在编译期间将注解信息编译到class文件中,然后在运行时通过反射机制获取注解信息,根据信息与注解规定进行逻辑处理。
元注解:注解的注解,就是给你自己定义的注解添加注解
取值(ElementType) | 作用 |
---|---|
ElementType.TYPE | 允许被修饰的注解作用在类、接口和枚举上 |
ElementType.FIELD | 允许作用在属性字段上 |
ElementType.METHOD | 允许作用在方法上 |
ElementType.PARAMETER | 允许作用在方法参数上 |
ElementType.CONSTRUCTOR | 允许作用在构造器上 |
ElementType.LOCAL_VARIABLE | 允许作用在本地局部变量上 |
ElementType.ANNOTATION_TYPE | 允许作用在注解上 |
ElementType.PACKAGE | 允许作用在包上 |
Java自定义注解使用@关键字定义新的Annotation类型,其中自定义注解默认继承了java.lang.annotation.Annotation接口。
在定义Annotation的成员变量时,需要以无参数方法的形式来声明,该方法名和返回值定义了该成员的名字和类型,称为配置参数,类型只能是基本数据类型、String类型、Class类型、枚举类型、注解类型及以上所有类型的数组,并可指定初始值,可以使用default关键字来指定成员变量的初始值。
小案例:在运行时通过反射获取类、字段和方法上的注解信息。
定义注解(该注解定义了两个属性:value和names,其中,value属性有默认值为空字符串,names属性有默认值为空数组)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
String value() default "";
String[] names() default {};
}
使用该注解时,可以像下面这样指定属性值:
@MyAnnotation(value = "hello", names = {"Jack", "Lucy"})
public void myMethod() {
// do something
}
测试下效果,在运行时,通过反射来获取注解的属性值
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = MyClassTest.class;
MyAnnotation methodAnnotation = clazz.getDeclaredMethod("myMethod").getAnnotation(MyAnnotation.class);
String methodValue = methodAnnotation.value();
String[] methodNames = methodAnnotation.names();
System.out.println("methodValue: " + methodValue);
for (String methodName : methodNames) {
System.out.println(methodName);
}
}
结果如下:
案例:扫描包内所有带注解的方法并执行。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Run {
}
public class MyClass {
@Run
public void myMethod1() {
// do something
System.out.println("我是被@Run注解的方法,我被执行了");
}
public void myMethod2() {
// do something
System.out.println("我是没有@Run注解的方法,我被执行了");
}
}
编写一个工具类,它可以扫描指定包中所有带有@Run注解的方法。
public class Runner {
public static void run(String packageName) throws Exception {
List<Class<?>> classes = getClasses(packageName);
for (Class<?> clazz : classes) {
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Run.class)) {
method.invoke(clazz.newInstance());
}
}
}
}
private static List<Class<?>> getClasses(String packageName) throws Exception {
List<Class<?>> classes = new ArrayList<>();
String path = packageName.replace(".", "/");
URL url = Thread.currentThread().getContextClassLoader().getResource(path);
if (url != null) {
File dir = new File(url.toURI());
for (File file : dir.listFiles()) {
String fileName = file.getName();
if (file.isDirectory()) {
classes.addAll(getClasses(packageName + "." + fileName));
} else if (fileName.endsWith(".class")) {
String className = packageName + "." + fileName.substring(0, fileName.length() - 6);
Class<?> clazz = Class.forName(className);
classes.add(clazz);
}
}
}
return classes;
}
}
测试代码是否顺利将com.example包内所有带@Run注解的方法执行:
public class Test {
public static void main(String[] args) throws Exception {
Runner.run("com.example");
}
}
结果如下