现在的位置: 首页 > 综合 > 正文

JavaSE 拾遗(17)——JavaSE 高新技术基础增强…注解

2018年01月10日 ⁄ 综合 ⁄ 共 5535字 ⁄ 字号 评论关闭
文章目录

注解的了解和入门

注解是 jdk1.5 的新特性

什么是注解

注解就相当于标签,给什么什么加上注解就相当于给什么什么贴上标签,这个标签在 编译、加载、JVM 执行的某个阶段可以读出来使用,判断加标签元素的具有某方面的属性。因为标签这种东西仍然可以是对象,所以在 java 里面,注解定义的源字节码加载到 JVM 后对应一个 Class 对象,使用注解的地方,是一个该注解类型的对象。但是注解对象是一种特殊的对象,它是用来修饰 包、类、成员方法、成员变量、注解 等 Class 成员的对象。并且如果想要在我们程序中引用这种对象,只能通过注解对象修饰过的类的 Class 对象来获取。注解对象仍然是一个
Object 的对象,这说明注解类型 extends Object。

Annotation(注解)是JDK5.0及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,执行基本编译时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。另外,你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件中出现,或者它还可以再运行时中存在。

注解实例

java.lang 包下面的注解

@SurpressWarnings 告诉编译器废弃警告

@Deprecated 告诉编译器那个成员过时了

@Override 告诉编译器这是在实现函数重载

public class AnnotationDemo {

	/** 
	 * @method: main
	 * @description: TODO
	 * @param args
	 * @return: void
	 * @author: vivianZhao
	 * @date: 2013-7-22 下午3:43:14
	 * @version: 1.0
	 */
	@SuppressWarnings("deprecation")
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.runFinalizersOnExit(true);
		
	}
	
	@Deprecated
	public static void printHello() {
		System.out.println("Hello World");
	}
	
	@Override
	public String toString(){
		return null;
	}

}

总结:注解是一种特殊的类,注解相当于是一种标记,加了注解等于打上了某种标记,没加,就没有某种标记,javac 进行编译器、开发工具和其他程序可以通过反射来了解你的类及其各种元素上的注解这种属性,并根据注解这种属性做相应的操作。注解这种标记可以加载 包、类、字段、方法、方法的参数以及局部变量上。

注解的定义、使用与反射注解

1.自定义一个简单的注解

/**
 * 需求:自定义一个注解类型
 */
package cn.itcast.annocation;

/**
 * @class: MyAnnotation
 * @package: cn.itcast.annocation
 * @description: 自定义的一个注解类型
 * @author: vivianZhao
 * @date: 2013-7-22 下午5:20:31
 * @version: 1.0
 */
public @interface MyAnnotation {

}

2.把这个注解用在某个类上面

/**
 * 需求:使用我自己的注解
 */
package cn.itcast.annocation;

/**
 * @class: MyAnnotationTest
 * @package: cn.itcast.annocation
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-22 下午5:22:30
 * @version: 1.0
 */
@MyAnnotation // 这就相当于使用自定义的注解类型,在 Class 解析的时候可以把这解析为注解对象
public class MyAnnotationTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}

3.使用反射获取这个注解

/**
 * 需求:使用我自己的注解
 */
package cn.itcast.annocation;


/**
 * @class: MyAnnotationTest
 * @package: cn.itcast.annocation
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-22 下午5:22:30
 * @version: 1.0
 */
@MyAnnotation
// 这就相当于使用自定义的注解类型,但在 Class 解析的时候可以把这解析为注解对象
public class MyAnnotationTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 判断某个类的修饰中是否存在 某个 Annotation 修饰
		if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
			// 如果存在该 Annotation 修饰,那么获取该 Annotation 的对象,跟获取 Method、Feild 对象一样
			MyAnnotation myAnnotationObject = (MyAnnotation)MyAnnotationTest.class
					.getAnnotation(MyAnnotation.class);
			System.out.println(myAnnotationObject);
		}
	}

}

打印结果啥都没有,说明 JVM 判断这个类的修饰中不存在某个 MyAnnotation 修饰,主要原因是 Annotation 是有生命周期的,默认都只存在于 编译阶段,生命周期使用元注解 @Retention 来表示,在 MyAnnotation 的定义上使用 @Retention(value = RetentionPolicy.RUNTIME),或者  @Retention(RetentionPolicy.RUNTIME) 修饰之后,打印结果为:

@cn.itcast.annocation.MyAnnotation()

4.元注解

元注解就和元数据、元类型一样,因为注解上面也可以有注解,元注解就是最基本的注解,只用于注解上面的注解

@Retention

注释类型 Retention

@Documented
@Retention(value=RUNTIME)                // 说明这个注解保持到运行时阶段
@Target(value=ANNOTATION_TYPE)  // 这说明这个注解只用于注解上面
public @interface Retention

指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。 只有元注释类型直接用于注释时,Target 元注释才有效。如果元注释类型用作另一种注释类型的成员,则无效。

@Target

注释类型 Target

@Documented
@Retention(value=RUNTIME)               // 说明这个注解保持到运行时阶段
@Target(value=ANNOTATION_TYPE) // 这说明这个注解只用于注解上面
public @interface Target

指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。默认为所有类型上都可以使用。

这里引出了 ElementType 类型的枚举

Type 接口

Type 是 Java 编程语言中所有类型的公共高级接口。它们包括原始类型、参数化类型、数组类型、类型变量和基本类型。 Class 是其子类。class、interface、enum、@interface 定义的结构,在内存里面都是 Class 类型对象。所以 @interface 定义的 annotation 才可以使用反射来操作。

Type 下的类型可以分为两类,基本类型和引用类型,其中引用类型也可以分为好多种,class 定义的类型、interface 定义的类型、enum 定义的类型、数组类型、@interface 定义的类型,引用类型在内存中都对应一个类型的 Class 对象,Class 类型仍然继承自 Object 类型。@interface 定义的类型的对象也继承自 Object 对象,所以我觉得 @interface 定义的类型和 enum 定义的类型一样是一个特殊的
class 类型。
因为这样 @interface 定义注解的时候,还可以嵌套定义枚举类型,也可以为注解添加访问修饰符。比如:

public @interface Greeting {
	//定义枚举类型
	public enum FontColor{
	BLUE,RED,GREEN
	};
	String name();
	FontColor fontColor() default FontColor.RED;
}

为注解增加各种类型的属性

一个注解相当于一个胸牌,如果你胸前贴了胸牌,就是传智播客的学生,否则,就不是。如果还想区分出是传智播客哪个班的学生,这时候可以为胸牌在增加一个属性来进行区分。加了属性的标记使用实例如:@MyAnnotation(color="red")。

1.添加属性之后的 MyAnnotatin

@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	String color(); 
	// 注解的属性的声明和接口的方法的声明格式差不多,我认为注解的属性声明好比是类中 getter setter 和属性声
	// 明的简写形式
}

2.在类上使用有属性的注解和用反射获取有属性注解的属性值

/**
 * 需求:演示在类上使用有属性的注解和用反射获取有属性注解的属性值
 */
package cn.itcast.annocation;


/**
 * @class: MyAnnotationTest
 * @package: cn.itcast.annocation
 * @description: TODO
 * @author: vivianZhao
 * @date: 2013-7-22 下午5:22:30
 * @version: 1.0
 */
@MyAnnotation(color = "red")
// 这就相当于使用自定义的注解类型,但在 Class 解析的时候可以把这解析为注解对象
public class MyAnnotationTest {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 判断某个类的修饰中是否存在 某个 Annotation 修饰
		if (MyAnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
			// 如果存在该 Annotation 修饰,那么通过 Class 反射获取该 Annotation 的对象,跟获取 Method、Feild 对象一样
			MyAnnotation myAnnotationObject = (MyAnnotation)MyAnnotationTest.class
					.getAnnotation(MyAnnotation.class);
			// 使用该 Annotation 对象
			System.out.println(myAnnotationObject.color());
		}
	}
}

打印结果为:red

3.注解的 value 属性和为注解属性指定缺省值

如果注解只有 value 属性可以设置,那么在使用该注解的时候就可以不用添加属性和等号,如:@MyAnnotation("red");

4注解的数组类型的属性、枚举类型的属性、注解类型的属性

数组类型的属性
定义注解:int [] arrayAttr() default {1, 2, 3};
使用:@MyAnnotation(arrayAttr = { 2, 3,4})
如果数组属性中只有一个元素,这时候属性值部分可以省略大括号,如:@MyAnnotation(arrayAttr = 2)
枚举类型属性
定义注解:TrafficLamp lamp() default TrafficLamp.RED;
使用:@MyAnnotation( lamp = TrafficLamp.RED)

注解类型属性
定义注解:Retention annotation() default @Retention(RetentionPolicy.RUNTIME);
使用: @MyAnnotation(annotation = @Retention(RetentionPolicy.RUNTIME));
注解不能定义自己类型的注解属性,因为在给该属性赋值的时候形成无限了递归
Class类型属性
为什么单独创建一个 @interface 类型,来表示 class method field  等的属性,而不用以前一样的内部的东西来表示属性呢,这个有点像 C 里面的宏定义,用来控制编译器的行为,只不过注解更强大,不但可以用来控制 javac 的行为,还可以用来控制 ClassLoader 的行为,还可以在 JVM 执行程序的时候,用源程序来读取 @interface 来控制源程序的行为。

抱歉!评论已关闭.