首页 > 代码库 > Java注释(注解)简介

Java注释(注解)简介

1、介绍

从JDK5.0开始,Java增加了对元数据(MetaData)的支持,也就是Annotation。其实就是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。

通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证

或者进行部署。

Annotation不影响程序代码的执行,无论增加、删除Annotation,代码都始终如一的执行。如果希望让程序中的Annotation能在运行时起一定的作用,只有通过某种配套的

工具对Annotation中的信息进行访问和处理,访问和处理Annotation的工具统称为APT(Annotation Processing Tool)。


2、原理

http://rejoy.iteye.com/blog/1627355

http://blog.csdn.net/blueheart20/article/details/18810693

可以参考JDK源码看其实现原理


3、使用

基本的Annotation

@Override:仅用来指定覆盖方法的,它强制一个子类必须要覆盖父类的方法。

@Deprecated:表示某个程序元素(类、方法等)已过时,当其他程序使用已过时的类、方法时,编译器将会给出警告。比如标记父类中的某个方法过时。

@SuppressWarnings("unchecked"):表示被Annotation标示的程序元素(以及在该程序元素中的所有子元素)取消显示指定的编译器警告。


自定义Annotation

使用关键字@interface

package com.java.anotion;


public @interface MyAnnotation {

//定义了两个变量的Annotation,default是默认值。

String name() default "cheney";

int age() default 18;

}


Annotation分为两类:

1、标记Annotation,没有成员定义,用自身的是否存在来为我们提供信息。

2、元数据Annotation,包含成员变量的Annotation,他们可以接受更多的元数据,所以被成为元数据Annotation。


提取Annotation的信息

java.lang.reflect新增的接口AnnotatedElement接口,该接口被主要的反射类实现,如Class,Constructor,Field,Method,Package等。通过反射类可以获取实现类的注释等信息。


两个示例:

示例一

package com.java.anotion;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

/**
 * 空注释
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Testable {
}
package com.java.anotion;

import java.lang.reflect.Method;

/**
 *@Testable注释处理工具类 
 */
public class TestProcessor {
	
	/**
	 * 反射clazz调用的时候要加上报名称路径,不然会包找不到类异常
	 * @param clazz
	 * @throws SecurityException
	 * @throws ClassNotFoundException
	 */
	public static void process(String clazz) throws SecurityException, ClassNotFoundException{
		int passed = 0;
		int failed = 0;
		for(Method m : Class.forName(clazz).getMethods()){
			if(m.isAnnotationPresent(Testable.class)){
				try {
					m.invoke(null);
					passed++;
				} catch (Exception e) {
					System.out.println("方法" + m + "运行失败,异常:" + e.getCause());
					failed++;
				}
			}
		}
		System.out.println("共运行了" + (passed + failed) + "方法,其中成功的" 
				+ passed + "个,失败的" + failed + "个");
	}
}
package com.java.anotion;

/**
 * 注释@Testable的目标类
 */
public class TestableAnnotationTest {
	@Testable
	public static void method1(){
		
	}
	public static void method2(){
		
	}
	
	@Testable
	public static void method3(){
		throw new RuntimeException("method3 RuntimeException");
	}
	public static void method4(){
		
	}
	
	@Testable
	public static void method5(){
		
	}
	public static void method6(){
		
	}
	
	@Testable
	public static void method7(){
		throw new RuntimeException("method7 RuntimeException");
	}
	@Testable
	public static void method8(){
		
	}
}
package com.java.anotion;

import java.util.ArrayList;
import java.util.List;

/**
 * @author youyang
 *
 *
 */

public class Test extends Fruit{
	
	@MyAnnotation(name="ch",age=6)
	public void foo(){
		System.out.println("еfoo");
	}
	
	
	@SuppressWarnings("unchecked")
	public static void main(String[] args) throws Exception {
//		new Test().foo();
//		List<String> list = new ArrayList();
		TestProcessor.process("com.java.anotion.TestableAnnotationTest");
	}
}

示例二

package com.java.anotion;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;

/**
 * 带成员变量的注释
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ActionListenerFor {
	String listener();
}

    

package com.java.anotion;

import java.awt.event.ActionListener;
import java.lang.reflect.Field;

import javax.swing.AbstractButton;

public class ActionListenerInstaller {
	public static void processAnnotations(Object obj){
		Class cl = obj.getClass();
		for(Field f : cl.getDeclaredFields()){
			//讲指定Field设置为可自由访问的,避免private的不可访问
			f.setAccessible(true);
			//获取指定Filed的ActionListenerFor类型的注释
			ActionListenerFor a = f.getAnnotation(ActionListenerFor.class);
			if(a != null){
				try {
					Class listenerClass = Class.forName(a.listener());
					ActionListener al = (ActionListener) listenerClass.newInstance();
					AbstractButton ab = (AbstractButton) f.get(obj);
					ab.addActionListener(al);
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
package com.java.anotion;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class AnnotationTest {
	private JFrame jFrame = new JFrame("使用注释绑定事件监听器");
	//引用内部类的时候com.java.anotion.AnnotationTest$OkListenter反射不成功,报错
	@ActionListenerFor(listener="com.java.anotion.OkListenter")
	private JButton ok = new JButton("确定");
	@ActionListenerFor(listener="com.java.anotion.CancelListenter")
	private JButton cancel = new JButton("取消");
	
	public void init(){
		JPanel jp = new JPanel();
		jp.add(ok);
		jp.add(cancel);
		jFrame.add(jp);
		ActionListenerInstaller.processAnnotations(this);
		jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jFrame.setLocation(300, 200);
		jFrame.setSize(500, 300);
		jFrame.setVisible(true);
		
	}
	
	public static void main(String[] args) {
		new AnnotationTest().init();
	}
	/*
	class OkListenter implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			JOptionPane.showMessageDialog(null, "点击了确认按钮");
		}
	}
	class CancelListenter implements ActionListener{
		public void actionPerformed(ActionEvent e) {
			JOptionPane.showMessageDialog(null, "点击了取消按钮");
		}
	}
	*/
}
package com.java.anotion;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;

public class CancelListenter implements ActionListener{
	public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(null, "点击了取消按钮");
	}
}
package com.java.anotion;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JOptionPane;

public class OkListenter implements ActionListener{
	public void actionPerformed(ActionEvent e) {
		JOptionPane.showMessageDialog(null, "点击了确认按钮");
	}
}

JDK的元Annotation

在java.lang.annotation包下提供了四个元Annotation。

@Retention:用于指定该Annotation可以保留多长时间。包含一个RetentionPolicy类型的value成员变量。

value有三个值:

1、RetentionPolicy.CLASS 编译器将把注释记录在class文件中。当运行Java程序时,JVM不再保留注释。这是默认值。

2、RetentionPolicy.RUNTIME 编译器把注释记录在class文件中。当运行Java程序时,JVM也会保留注释,程序可以通过反射获取该注释。

3、RetentionPolicy.SOURCE 编译器直接丢弃这种策略的注释。

注:如果Annotation类型只有一个value成员变量,可以直接写value值,不用name=value的形式。


@Target:用于指定该Annotation修饰哪些程序元素。也包含一个ElementType类型的value成员变量。

value值有8个:

ElementType.ANNOTATION_TYPE只能修饰Annotation

ElementType.CONSTRUCTOR修饰构造器

ElementType.FIELD修饰成员变量

ElementType.LOCAL_VARIABLE修饰局部变量

ElementType.METHOD修饰方法定义

ElementType.PACKAGE修饰包定义

ElementType.PARAMETER修饰参数

ElementType.TYPE修饰类、接口或枚举定义


@Documented: 用于呗javadoc工具提取成文档,如果注释了提前的文档说明会有注释,否则没有。


@Inherited:指定被它修饰的Annotation将具有继承性。基类如有@Inherited,继承此基类的类也有此annotation。


4、提高

使用APT处理Annotation

APT(annotation processing tool)是一种处理注释工具。它对源文件进行检测找出其中的Annotation后,使用Annotation进行额外的处理。

Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其他的文件(文件具体内容由Annotation处理器的编写者决定),APT还会编译

生成的源代码文件和原来的源文件,将它们一起生成class文件。

使用APT主要目的是简化开发者的工作量,因为APT可以在编译程序源代码的同时,生成一些附属文件(比如源文件、类文件、程序发布描述文件等),这些附属文件的内容

也都是与源代码相关的。换句话说,使用APT可以代替传统的对代码信息和附属文件的维护工作。


为了是系统的APT工具读取源文件中的Annotation,必须自定义一个Annotation处理器,编写处理器需要JDK lib目录中的tools.jar里的如下四个包:

com.sun.mirror.apt:和APT交互的接口

com.sun.mirror.declaration:包含各种封装类成员、类方法、类声明的接口

com.sun.mirror.type:包含各种封装源代码中程序元素的接口。

com.sun.mirror.util:提供了用于处理类型和声明的一些工具。


对于APT的使用,比如hibernate自动生成的bean属性文件xxx.xxx.xml,实现原理就是APT。编写自己的Annotation,

在bean类中引用自定义Annotation,系统会调用APT生成响应的配置文件。



本文出自 “风云海滩” 博客,请务必保留此出处http://3950566.blog.51cto.com/3940566/1562371

Java注释(注解)简介