(本来要读一下PendingIntent的源码,发现好多注解,所以就脑补了下注解)
一.什么是注解?
在JDK1.5后java开始了对元数据(Metadata)的支持,也就是注解(Annotation)。关于Metadata的介绍:
Metadata is "data that provides information about other data".Two types of metadata exist: structural metadata and descriptive metadata. Structural metadata is data about the containers of data. Descriptive metadata uses individual instances of application data or the data content[1].
摘自 网址 https://en.wikipedia.org/wiki/Metadata
大致意思是说:
元数据是一种用来为其它数据提供数据的数据。元数据有两种形式:结构元数据和描述性元数据。其实,在java中所谓元数据(注解)就是包含了接口、类、方法和变量的一些信息,或者元数据是对接口、类、方法、变量等等作得的标记。这些标记在将来可以在编译、类加载、运行时读取出来,根据标记的不同,对它所标记的数据进行特别的处理。
二.既然它是一种标记,那么它可以用来标记哪些数据呢?
包、接口、类、构造方法、方法、字段、参数、局部变量。
三.注解和注释
注释:1)它是对一些代码的描述,主要目的是为了提高代码的可读性,为自己和其他程序员阅读代码提供便利。
2)注释不能被编译,更不能加载和执行。
注解:1)它虽然是一种其它代码的标记,但是它自身也是一段程序代码,能够被编译,能够被jvm解释执行。
相同点:他们的改变并不影响其他代码的执行,无论是增加还是删除,其他被他们修饰的代码都能顺利运行(这句 话并不严谨)
四.jdk中提供的注解:
1)@Override
它的作用是用来指定方法覆载的,它强制一个子类必须覆盖父类的方法。当一个子类的方法被@Override修饰时,编译时,编译器就会到其父类中寻找这个方法,如果没有找到就会后编译错误。
2)@Deprecated
当一个类或者方法被@Deprecated修饰后,就意味这它已经过时了,不再推荐使用。如果继续使用就出编译器就会发出警告。
3)@Suppress Warnings
它的作用是抑制编译器的警告。比如上面如果出现方法过期的编译时警告,如果我们想要将警告取消,我们就可以使用@SuppressWarnings("deprecation")对相应的方法进行修饰。
4)@Safe Varargs (JDK 1.7) 抑制对污染警告
5)@FunctionalInterface(JDK 1.8)
用来告诉编译器,该接口只能包括一个抽象方法。(该注解只能用于修饰接口)
五.元注解(Meta Annotation)
顾名思义,元注解就是用来修饰注解的注解,用于注解的定义。
1.四个的元注解:
1)@Retention
作用:用来规定被它修饰的注解的生命范围
** RetentionPolicy.RUNTIME
编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。
** RetentionPolicy.CLASS
编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。这是默认的行为。
** RetentionPolicy.SOURCE
编译器要丢弃的注释。
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
注:1.JDK提供的五种基本注解的生命期为RetentionPolicy.CLASS
2.RetentionPolicy是一个枚举。
3.@Retention只能用于修饰注解的定义,用于修饰注解可以保留多长时间。
4.由源码可看出,@Retention只能接收一个参数。
2)@Target
作用:用来规定被它修饰的注解所能修饰的程序元素
** ElementType.ANNOTATION_TYPE
被它修饰的注解只能用于修饰注解定义
** ElementType.CONSTRUCTOR
被它修饰的注解只能用于修饰构造方法定义
** ElementType.FIELD
被它修饰的注解只能用于修饰字段定义
** ElementType.LOCAL_VARIABLE
被它修饰的注解只能用于修饰局部变量定义
** ElementType.METHOD
被它修饰的注解只能用于修饰方法定义
** ElementType.PACKAGE
被它修饰的注解只能用于修饰包定义
** ElementType.PARAMETER
被它修饰的注解只能用于修饰参数定义
** ElementType.TYPE
被它修饰的注解只能用于修饰类、接口、枚举定义
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
注:由源码可看出,@Target可接收多个参数。
3)@Documented
作用:用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。如果一个程序元素被一个被@Documented所修饰的注解修饰,那么该程序元素的API文档中将会包括该注解的说明。
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
注: @Documented是一个标记注解,没有成员。
4)@Inherited
作用:@Inherited 是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
源码:
<span style="font-size:18px;"> @Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}</span>
注: @Inherited 是一个标记注解,没有成员
六、自定义注解
1、格式
public @interface 注解名 {定义体}
说明:
1)就像定义类用class关键字,定义注解用@interface关键字。
2)权限修饰符和类名的原则与类或接口相同。
3)定义体:如下。
2.关于定义体的说明:
1)定义体中主要作用是规定将来的自定义注解的参数类型及名称,定义体可以是空的。
2)注解的参数类型主要包括:
*基本数据类型(byte、short、int、long、float、double、char和boolean)
*String类型
*Class类型
*enum类型
*Annotation类型
*以上类型的数组
3)参数的权限修饰符只能用public或者默认。
4)如果定义体中只有一个参数,最好把它命名为value,如String value()。
5)如4中的String value(),括号里不能有参数,并且后面不能抛异常。
3 自定义注解举例:
1)
@Target(ElementType.METHOD)
public @interface Test1{
}
说明:定义了一个注解Test1,它的修饰对象是方法,并且没有参数。
2)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Test2{
int id() default -1;
String name();
}
说明: 定义了一个注解Test2,它的修饰对象是字段,有两个参数:id (默认值为-1)、name。
**第一种没有参数的的Annotation我们称它们为标记注解。标记注解仅仅通过自身存在与否来提供信息(类似于标记接口)。
**第二种带有参数的Annotation我们称它们为元数据注解。
七、注解的解析
描述:通过反射来获取类、方法或成员上的运行时注解,从而动态控制程序运行的逻辑。
自定义注解Test代码:
package test5;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Test {
String value();
}
Student代码:
package test5;
@Test("this is a student.")
public class Student {
}
测试类:
package test5;
public class AnnitationDemo {
public static void main(String[] args) {
Class<?> s = null;
Test t = null;
// 第一步,使用类加载器加载Student类
try {
s = Class.forName("test5.Student");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 第二步,判断Student上是否有叫做“Test”的注解,如果有取出来
if (s != null && s.isAnnotationPresent(Test.class)) {
t = s.getAnnotation(Test.class);
}
// 第三步,控制台打印注解
System.out.println("注解——" + t.value());
}
}
结果:
八、本文参考
1 > 李刚 《疯狂java讲义》 (第三版)
2 >竹子 《深入理解Java:注解(Annotation)自定义注解入门》
http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html