码迷,mamicode.com
首页 > 其他好文 > 详细

注解(Annotation)

时间:2015-05-30 12:15:13      阅读:171      评论:0      收藏:0      [点我收藏+]

标签:注解   annotation   deprecated   自定义注解   元注解   

入门

注解,英文叫做Annotation。是和枚举,类,接口类似的包成员概念。之所以每个注解都加一个@字符,是因为在英文中,@=at,而AT正好是Annotation中的两个字母,所以@就直接当做Annotation的缩写了。 java.lang包提供了三个基本注解,如下:

@SuppressWarings

@SuppressWarings注解,表示不对指定的问题进行警告。用法如下:
public class AnnotationTest {
	@SuppressWarnings("deprecation")//deprecation表示废弃,此行表示不对废弃的方法警告
	public static void main(String[] args) {
		System.runFinalizersOnExit(true);
	}
}
上面代码片中的第2行,表示不对废弃的方法进行警告。runFinalizersOnExit()是废弃的方法(表示方法已过时,但为了兼容老代码而保留),不加注解情况下,在MyEclipse中会在方法名字上显示中划线,在调用方法的行上会显示警告图标。用jdk的javac编译,会给出警告。但是加了@SuppressWarings注解后,MyEclipse会去掉中划线,javac编译后也不会显示警告。

@Deprecated

@Deprecated注解,表示下面的方法被废弃。用法如下:
public class AnnotationTest {
	public static void main(String[] args) {
		sayHello();
	}
	@Deprecated//Deprecated单词表示被废弃的,此行代码表示sayHello方法已被废弃
	public static void sayHello(){
		System.out.println("Hello world!");
	}
}

@Override

@Override注解,表示下面的方法是重写父类的方法,如果没重写成功,编译会报错。示例如下:
public class ReflectPoint {
	int x;
	int y;
	public ReflectPoint(int x,int y) {
		this.x=x;
		this.y=y;
		System.out.println(this.hashCode());
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ReflectPoint other = (ReflectPoint) obj;
		if (x != other.x)
			return false;
		if (y != other.y)
			return false;
		return true;
	}
}
上面的代码中@Overrider表示紧接着的方法是重写父类的方法,相当于告诉编译器,如果下面的方法不是重写父类的方法,请报错,这样 
可以防止参数类型没写准确而没有成功的重写父类的方法的问题。

注解的定义与反射调用

在MyEclipse中新建一个注解类很简单,只需在包上右击,选择New→Annotation, 这样就建好了一个基本的注解,如下:
public @interface MyAnnotation {
	
}
可见@interface就是定义注解的关键词。由此可见注解时一种特殊的接口。
然后让我们试试反射注解
@MyAnnotation
public class AnnotationTest {
	public static void main(String[] args) {
		//检查AnnotationTest类上是否有MyAnnotation注解
		if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
			//获取AnnotationTest类的MyAnnotation注解
			MyAnnotation annotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
			System.out.println(annotation);
		}
	}
}
上面的代码运行后什么也不会输出,别急,因为出现这种情况是因为注解缺少东西。

@Retention

@Retention注解用于指定下面的注解的生命周期。它的唯一参数有三个取值:
RetetionPolicy.SOURCE:表示指定的注解只在.java源文件中起作用,这个注解不会被编译进jar包
RetetionPolicy.CLASS:表示指定的注解会被编译进jar包,但是不能被反射。这个是默认值。
RetetionPolicy.RUNTIME:表示注解会连同宿主类被加载进内存,只有定义注解时,指定了这个参数,注解才能被反射。
另外@Retention是加在注解上的注解,这种注解叫元注解

反射注解

接着上面的代码,将注解定义改为如下:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
	
}
然后再运行下面的反射代码:
@MyAnnotation
public class AnnotationTest {
	public static void main(String[] args) {
		//检查AnnotationTest类上是否有MyAnnotation注解
		if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
			//获取AnnotationTest类的MyAnnotation注解
			MyAnnotation annotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
			System.out.println(annotation);
		}
	}
}
输出结果@cn.itcase.day2.MyAnnotation(),其中cn.itcase.day2是包名

@Target

@Target用于指定注解的作用对象,唯一参数的可能值是:
ElementType.METHOD:表示只能只能作用于方法。
ElementType.TYPE:表示只能作用于与类平级的类型,如类、接口、注解、枚举
ElementType.FIELD:表示只能作用于字段声明
用法示例如下:
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.METHOD)
public @interface MyAnnotation {
	
}
如果需要给Target加多个参数则需这么写
@Target({ElementType.METHOD,ElementType.TYPE})

为注解增加‘属性’

由于注解的本质是个接口,所以注解的‘属性’就是接口的方法。简单的例子如下:
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.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
	String color();
}
上面的代码为MyAnnotation注解增加了一个属性color,这样就可以在调用注解的地方制定这个属性。如下:
@MyAnnotation(color="blue")
public class AnnotationTest {
	public static void main(String[] args) {
		//检查AnnotationTest类上是否有MyAnnotation注解
		if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
			//获取AnnotationTest类的MyAnnotation注解
			MyAnnotation annotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
			System.out.println(annotation);
			System.out.println(annotation.color());
		}
	}
}
还可以为注解制定默认值,如下:
public @interface MyAnnotation {
	String color() default "blue";
}
这样调用注解时,就可以不写参数,如下:
@MyAnnotation()或@MyAnnotation
注解还有一个特殊的属性value,定义方法如下:
public @interface MyAnnotation {
	String color() default "blue";
	String value();
}
这时就可以这样调用注解
@MyAnnotation("Hello")
注意到value的特殊之处是可以不写属性名,而其他属性在调用赋值时,都必须写属性名。
注解的属性可以使任意数据类型,下面用数据举例:
public @interface MyAnnotation {
	String color() default "blue";
	String value();
	int[] arrayAttr() default {1,2,3}; 
}
调用方法如下:
@MyAnnotation(color="blue",value="Hello",arrayAttr={2,1,3})
或@MyAnnotation("Hello")
但是@MyAnnotation("Hello",arrayAttr={2,1,3})的写法是错误,注解的参数要么全写属性名,要么全不写,不能混搭

枚举类型属性

在注解中定义枚举类型属性的方法如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
	EnumDemo.TrafficLamp lamp() default EnumDemo.TrafficLamp.GREEN;
}
其中的枚举EnumDemo.TrafficLamp源码如下:
public class EnumDemo {
	/**
	 * 交通灯枚举
	 * @author programBoy
	 */
	public enum TrafficLamp{
		GREEN{
			public TrafficLamp getNext() {
				return YELLOW;
			}
		},
		RED{
			public TrafficLamp getNext() {
				return GREEN;
			}
		},
		YELLOW{
			public TrafficLamp getNext() {
				return RED;
			}
		};
		public abstract TrafficLamp getNext();
	}
}
然后调用注解,并反射注解,进行测试,代码如下:
@MyAnnotation
public class AnnotationTest {
	public static void main(String[] args) {
		//检查AnnotationTest类上是否有MyAnnotation注解
		if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
			//获取AnnotationTest类的MyAnnotation注解
			MyAnnotation annotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
			System.out.println(annotation);
			System.out.println(annotation.lamp().getNext().name());
		}
	}
}
由于注解的属性lamp有默认值,所以此处不用写此参数。运行上面的代码,结果如下:
@cn.itcase.day2.MyAnnotation(lamp=GREEN)
YELLOW
可见lamp属性在编译时被加上了默认值,只是源代码不用写而已

注解类型属性

首先再定义一个注解,如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface AttrAnnotation {//注意此处必须加public,否则反射不出来
	String value();
}

然后在MyAnnotation注解里定义一个注解类型的属性,如下:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnnotation {
	AttrAnnotation annotationAttribute() default @AttrAnnotation("Hello"); //当注解被当做类型使用时,不需要加@符号,当注解需要被实例化时,才需要加@符号。
}
然后调用MyAnnotation注解,并反射其中的注解属性:

@MyAnnotation(annotationAttribute=@AttrAnnotation("雷军"))
public class AnnotationTest {
	public static void main(String[] args) {
		//检查AnnotationTest类上是否有MyAnnotation注解
		if(AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)){
			//获取AnnotationTest类的MyAnnotation注解
			MyAnnotation annotation=(MyAnnotation)AnnotationTest.class.getAnnotation(MyAnnotation.class);
			System.out.println(annotation);
			System.out.println(annotation.annotationAttribute().value());
		}
	}
}
该程序运行结果如下:

@cn.itcase.day2.MyAnnotation(annotationAttribute=@cn.itcase.day2.AttrAnnotation(value=雷军))
雷军

注解(Annotation)

标签:注解   annotation   deprecated   自定义注解   元注解   

原文地址:http://blog.csdn.net/joven0/article/details/46272421

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!