`

JavaSE学习笔记--Annotation

阅读更多
1、annotation是什么?:
Java注解提供了一套机制,让我们可以对类、方法、参数、包、域及变量等添加标准(即附加某些信息),且可以从源文件、class文件或者以在运行时反射的多种方式被读取。

2、常见的annotation:
a) Override注解表示子类要重写父类的对应方法。
b) Deprecated注解表示方法是不建议被使用的。
c) SuppressWarnings注解表示压制警告。

3、自定义注解:
当注解中的属性名为value时,在对其赋值时可以不指定属性的名称而直接写上属性值即可;除了value以外的其他值都需要使用nam=value这种赋值方式,即明确指定给谁赋值。

自定义注解需注意的三点:
a) 当我们使用@interface自定义annotation时,实际上是隐含地继承了java.lang.annotation.Annotation接口。
b) 如果我们定义一个接口,并让该接口继承java.lang.annotation.Annotation接口,那么我们所定义的接口依然是一个接口,而不是注解。
c) Annotation本身是一个接口,而不是注解。

4、告知编译程序如何处理@Retention:
java.lang.annotation.Retention型态可以在你定义Annotation型态时,指示编译程序该如何对待你的自定义的Annotation型态,预设上编译程序会将Annotation信息留在.class文件中,但不会被虚拟机读取,而仅仅用于编译程序或工具程序运行时提供信息。

在使用Retention时,需要提供java.lang.annotation.RetentionPolicy的枚举类型
JDK中源码如下:
package java.lang.annotation;
public enum RetentionPolicy
{ 
    SOURCE,    //编译程序处理完Annotation信息后就完成任务,不会被编译到class文件中
    CLASS,       //编译程序将Annotation存储于class文件中,但不能被VM读取,缺省
    RUNTIME  //编译程序将Annotation存储于class文件中,可由VM读入,能通过反射读取到
}

RetentionPolicy为SOURCE的例子是@ SuppressWarnings
仅在编译时告知编译程序来抑制警告,所以不必把这个信息存储到.class文件中。

RetentionPolicy为RUNTIME的时机,可以像是你使用java设计一个代码分析工具,你必须让VM能读出Annotation信息,以便在分析程序时使用。搭配反射机制,就可以达到这个目的。

这时,我们来自定义一个注解,并将该注解标注为RUNTIME,然后通过反射来读取其注解的信息。

代码如下:

//自定义一个注解:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)//定义为RUNTIME可被反射读取
public @interface MyAnnotation 
{
	String hello() default "hello eric";
	String world();
}

//定义一个类,测试上面的注解:
public class MyTest 
{
	@MyAnnotation(world = "teng")
	public void output() 
	{
		System.out.println("output something");
	}
}

//写一个类通过反射API读取MyTest类中注解的信息
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class MyReflection 
{
	public static void main(String[] args) throws Exception
	{
		MyTest myTest = new MyTest();
		
		Class<MyTest> c = MyTest.class;
		
		Method method = c.getMethod("output", new Class[]{});
		
		//判断该方法上面是否有MyAnnotation这个注解
		if(method.isAnnotationPresent(MyAnnotation.class))
		{
			method.invoke(myTest, new Object[]{});
			
			MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
			String hello = myAnnotation.hello();
			String world = myAnnotation.world();
			
			System.out.println(hello);
			System.out.println(world);
		}

		//获取MyTest类中指定方法上的所有注解信息,并将其注解名打印出来
		Annotation[] annotations = method.getAnnotations();
		for(Annotation annotation : annotations)
		{
			System.out.println(annotation.annotationType().getName());
		}
	}
}


程序运行结果:
output something
hello eric
teng
com.annotation.MyAnnotation

5、@Target用来声明注解可以,被添加在哪些类型的元素上,如类型、方法和域等。在定义时要指定java.lang.annotation.ElementType的枚举值之一。
JDK中ElementType源码如下:
package java.lang.annotation
public enum ElementType
{
    Type,    //适用class,interface,enum
    FIELD,    //适用field
    METHOD,    //适用method
    PARAMETER,    //适用method里的parameter
    CONSTUCTOR,    //适用constructor
    LOCAL_VARIABLE,    //适用局部变量
    ANNOTATION_TYPE,    //适用annotation型态
    PACKAGE    //适用package
}


还是写一段代码来演示:
//自定义一个注解MyTarget:
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)//表示该注解只能修饰方法
public @interface MyTarget
{
	String hello();
}


//写个类测试该注解:
public class MyTargetTest
{
	@MyTarget(hello="eric")//如果将该注解放在类之上,就会报错
	public void doSomething()
	{
		System.out.println("mytarget test");
	}
}


6、子类是否继承父类@Inherited?
默认上父类中的Annotation并不会被子类继承。若想让子类继承父类的Annotation,可以在定义Annotation时加上java.lang.annotation.Inherited型态的Annotation。
0
1
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics