1. 概念
首先,要理解注解的作用。注解的作用很简单、明确,它就是一种标记。在程序中加入了注解,就等于为程序(例如:类、方法)打上了某种标记;没加注解,则表示没有加标记。以后,我们就可以在其它程序中通过反射来得到,加了注解的有哪些类,没加注解的有哪些类。这样就可以对这两种类进行不同的处理。
例如,我们可以在Spring中定义一个注解@SpringClazz,如果类上面打了这个注解,就代表这个类被Spring容器管理了,于是用到这个类时,我们的工厂要返回这个目标类的【代理对象】。当然,如果没有打这个注解,就代表这个类没有被Spring容器管理,于是我们的工厂直接返回目标类的对象。(详情可以看上一篇文章http://blog.csdn.net/wang379275614/article/details/47112195)
上面只是定义了一个最简单的注解,注解还有属性等,下面我们就简单、系统的介绍一下java中的注解。
2. 系统注解
在java.lang包下,我们可以看到jdk默认提供的三个注解:
3. 元注解
即,注解的注解,就是用在我们的注解定义上的注解。类似我们数据表中经常说的元数据。概念不再多说,这里介绍两个很重要的元注解@Retention与@Target。
Ø @Retention(指定注解的作用时机:源代码、编译时、运行时)
Ø @Target(指定注解的作用范围:类【Type】、方法。。。。)
例如@Override注解的定义如下:
@Retention指定注解作用的时机,代表了我们在哪个阶段来检查相应的目标注解。例如@Override注解一定是在源代码时就开始检测,如果我们写代码时不符合@Override的规范,肯定等不到编译,就会提示我们用法错误。它的值为RetentionPolicy枚举,枚举常量有如下几种:(不需要记住,在jdk api文档中随便找一个注解都能找到它)
@Target,指定注解作用的范围,如果我们指定作用范围为方法,那么我们就不能将该注解加到其它类型的元素上,例如加到类的上面就会报错。它的取值为ElementType枚举,枚举常量有如下几种:
4. 注解属性
例如我们定义了一个注解@Tsinghua来标识是清华大学的学生,但程序还需要知道你是清华大学哪个系的学生,我们就可以给@Tsinghua这个注解加一个department属性。如:@Tsinghua(department=”Math”)就可以表示你是清华大学数学系的学生。
5. 自定义注解
直接看代码:
5.1 自定义注解@TGBAnnotation:
- package com.tgb.TestAnnotation;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Target( { ElementType.METHOD, ElementType.TYPE })
- @Retention(RetentionPolicy.RUNTIME)
- public @interface TGBAnnotation {
- // 注解属性1
- String color() default "blue";
- // 注解属性2
- int[] score() default { 1, 2, 3 };
- }
上面这个注解有两个注解属性;在运行时起作用;可以加在类、方法两种元素上。
5.2 测试类AnnotationTest:
- package com.tgb.TestAnnotation;
- @TGBAnnotation(color = "class--->yellow", score = { 10, 20 })
- public class AnnotationTest {
- public static void main(String[] args) throws Exception {
- // 已废弃的方法,比较危险,但也能用
- System.runFinalizersOnExit(true);
- sayHi();
- }
- /*
- * 当我们版本升级时,不想删掉以前的代码,也不想注释大量的代码,就可以加上@Deprecated注解
- */
- @Deprecated
- public static void sayHello() {
- System.out.println("Hello world!");
- }
- /**
- * 测试注解
- */
- @TGBAnnotation(color = "method--->red")
- public static void sayHi() throws Exception {
- // 如果AnnotationTest这个类上存在注解ItCastAnnotation
- if (AnnotationTest.class.isAnnotationPresent(TGBAnnotation.class)) {
- // 得到AnnotationTest类上的ItCastAnnotation注解实例,进而可以获得注解上的属性
- TGBAnnotation annotation = AnnotationTest.class.getAnnotation(TGBAnnotation.class);
- TGBAnnotation annotation2 = AnnotationTest.class.getMethod("sayHi", null).getAnnotation(TGBAnnotation.class);
- System.err.println("annotation---->" + annotation.color());// 输出:class--->yellow
- System.err.println("annotation2--->" + annotation2.color());// 输出:method--->red
- int[] score = annotation.score();
- for (int i : score) {
- System.out.println(i);// 依次输出:10、20
- }
- }
- }
- }
6. 总结
注解的作用很简单、明确,它就是一种标记。例如加上Spring的某个注解来标识这个类由Spring容器管理,getBean时返回【代理对象】;没有加这个注解的表示没有加到Spring容器中,getBean时直接返回【目标对象】。此外,结合jdk默认自带注解与张孝祥老师的所言,.class文件中的东西不是“字节码”,当类加载器把.class文件加载到内存的过程中也会处理一些事(例如安全检查),处理完以后的加载到内存中的二进制东西才是字节码。