Java Annotations 注解和 Java Comments 正文,英文里查别很大,在中文中一字之差让人颇为费解。Java Comments 正文是随着 Java 语言的诞生就有的,意义明确,简略易懂,就是在源代码中的解释信息,通常用在帮忙代码编写人员了解代码。Java Annotations 呈现的较晚,在 Java 1.5(Java 5)中才引入,目前(2022 年)Java 部署的支流是 Java 8(Java 1.8),最新发行版是 Java 11(Java 1.11).
但 Java Annotations 注解的意义和作用就显得有些费解,比方官网文档中:
Annotations do not directly affect program semantics, but they do affect the way programs are treated by tools and libraries, which can in turn affect the semantics of the running program. Annotations can be read from source files, class files, or reflectively at run time.
Annotations 注解不会间接影响程序的语义,然而他们的确影响工具和库处理程序的形式,进而影响运行中的程序的语义。Annotations 注解能够从源文件,class 文件,或者运行时的反射中读取。
随着“工具和库处理程序”的风行,比方在 Java 开发中逐步风行的 Spring 全家桶等,处处可见的 @RequestXXX 等表述,让后生 Java Annotations 逐步走入开发者的视线。然则只言片语地要解释分明 Java Annotations 注解是什么货色及怎么作用或者工作的,却非易事。
咱们所主导的 Java 开发框架 GWA2 in Java(https://ufqi.com/dev/gwa2/)并没有过多地倚重 Java Annotations 注解,次要是在初期技术架构选型时,咱们考查了应用 Reflection 等相干技术时,发现其性能会降落平安受影响。
Due to 1) issues of performance and security of java.lang.reflection, We do not use it as routing or dynamic module invoking at present.
鉴于 Reflection 相干技术存在性能和平安相干方面问题,GWA2 in Java 目前没有思考将其作为路由和动静模块加载技术手段。
然而,Java 开发业界仿佛造成了一种站在“伟人肩膀”上搭积木式地的重叠,第一个扣子歪了大家也就一顺溜地持续歪上来,所谓性能和平安问题都是能够克服的,不能解决的局部也是在可承受范畴内,大快人心。
近期咱们接手了两个 Java 开发的二期我的项目,基于 Java Spring 全家桶,我的项目技术栈尽管是 Java,但其所依赖的各种第三方组件达到令人目迷五色的境地(如下图)。
Java Spring 组件套系
既然 Java Annotations 如此重要,天然要弄清楚,然而当咱们试图向一些工程师解释 Java Annotations 是什么、怎么样的时候,发现并不容易,一方面是 Java 语言自身的复杂性,另一方面是 Annotations 是下层利用,是可选项。通过一番搜寻、思考和探索,我感觉如下两个实例能够清晰地解释 Java Annotations 注解的基本原理和利用实际,答复了 Java Annotations 注解是什么,为什么和怎么样的问题。
实例 1. 用 Java Annotations 注解标记某个对象类、实例、办法和属性具备或不具备某个属性。
这个实例来自官网(https://docs.oracle.com/javas…)
e.g.1.1. SampleTestTag.java: 自定义一个 Java Annotation 注解对象,其中的 @Retention 和 @Target 是注解的注解,称之为“元注解”,注解类的什么是在名称前加“@”at 符号
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SampleTestTag {
}
e.g.1.2. FooBar.java: 创立一个对象类 FooBar,应用下面创立的 Java 注解 SampleTestTag
public class FooBar {
@SampleTestTag public static void m1() {}
public static void m2() {}
@SampleTestTag public static void m3() {throw new RuntimeException("Boom");
}
public static void m4() {}
@SampleTestTag public static void m5() {}
public static void m6() {}
@SampleTestTag public static void m7() {throw new RuntimeException("Crash");
}
public static void m8() {}
}
e.g.1.3. FooBarTest.java: 创立一个测试程序,调用对象类 FooBar, 测试 SampleTestTag 的辨别作用
import java.lang.reflect.*;
public class FooBarTest {
public static void main(String[] args) throws Exception {
int passed = 0, failed = 0;
for (Method m : Class.forName(args[0]).getMethods()) {if (m.isAnnotationPresent(SampleTestTag.class)) {
try {m.invoke(null);
passed++;
} catch (Throwable ex) {System.out.printf("Test %s failed: %s %n", m, ex.getCause());
failed++;
}
}
}
System.out.printf("Passed: %d, Failed %d%n", passed, failed);
}
}
该测试程序预期运行的后果大抵为:
$ java FooBarTest FooBar
Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom
Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash
Passed: 2, Failed 2
这个实例示意,通过自定义一个注解,能够将对象类的某些办法标记进去,外围办法是 isAnnotationPresent。这只是一个简略的实例,如果这个路子走得通,有这种简略的办法或范式,能够将对象类、实例、办法和属性进行分类,好像关上了潘多拉的盒子,赋予开发者无穷尽的分类能力。
当具备这种能力后,能够在运行时依据分类,让 A 类的运行,让 B 类的都熄火;在英国区运行 A 类,在北美运行 B 类;让 VIP 的运行 A 类,让非 VIP 的运行 B 类;让小孩看 A 类,让老人看 B 类,其他人看 C 类….
显然这种能力是弱小的,但同时其复杂性也显现出来了,开发者看到的代码和最终运行时的代码可能高度的 不–一–致。只管代码都摆在哪里,但具体跑那些代码须要看运行时的状态。由此造成了可怕的所见非所得。
实例 2. 用 Java Annotations 注解标记某个对象类、实例、办法和属性具备某个属性的某种赋值。
这是对实例 1 的进化和降级,如果实例 1 提供让某个对象具备或不具备,是与非的简略二元分类,则实例 2 将这种能力有限降级到让某个对象的领有某个属性,而且这个属性的赋值能够变幻无穷。
更多全文内容:两个实例解释分明 Java Annotations 注解 | -UFQI-Blog,https://ufqi.com/blog/gwa2-ja…