java反射机制&Annotation详解_III

Annotation注解

不直接影响代码语义
被看作类似程序的工具或者类库
对正在运行的程序语义有所影响
在运行时反射的多种方式被读取

元注解:

  元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited

常用的是@Target  和  @Retention

@Target:

   @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  取值(ElementType)有:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明


@Retention:

  @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

  取值(RetentionPoicy)有:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)



系统自带的几种 

Override注解表示子类要重写(override)父类的对应方法

Deprecated注解表示方法是不建议被使用的

Suppress Warnings注解表示抑制警告



可以自己定义注解@interface 可以声明各种属性,默认值(default),加载域(Retention),位置(targer)
使用反射来获取注解中的详细信息
不多说,直接上代码了
//使用@interface来声明一个注解(实际上是自动继承了java.lang.annotation.Annotation接口)  
//@Target(ElementType.METHOD)    //这个注解只能标注在method的方法上
public @interface AnnotationTest {
 String value1() default "hello"; //String类型的 使用defalut设置默认值
 EnumTest value2(); //枚举类型
 String[] value3();   //数组类型
}
/*如果注解里只定义了一个属性,名字是value,那么可以直接赋值,不需要使用name=value这种赋值方式*/
/*
public @interface AnnotationTest {  
    String value();  
}  
 
@AnnotationTest("test")  
public void method(){  
    System.out.println("usage of Annotation");  
}
但是我还是对自定义的注解有啥用没啥感觉
*/ 

来一个枚举类
public enum EnumTest {
  MON, TUE, WED, THU, FRI, SAT, SUN;
}


@Retention(RetentionPolicy.RUNTIME)  //Runtime级别的,表示运行时有效
public @interface MyAnnotation {
 String hello() default "hello,chicago";
 String world();
}

@Retention(RetentionPolicy.CLASS) //在class文件中有效
public @interface MyAnnotation2 {
 String hello() default "hello";
} 

public class Test {
 @SuppressWarnings("unchecked")
 @Deprecated
 @MyAnnotation2(hello="I'm not here")
 @MyAnnotation(world="world",hello="not default")
 public void TestMethod(){
  System.out.println("this is a method");
 }
 
 
 public static void main(String[] args) throws Exception {
  Test test=new Test();
  Class<Test> c=Test.class;
  Method method=c.getMethod("TestMethod", new Class[]{});
 
  //AnnotatedElement接口中的方法isAnnotationPresent(),判断传入的注解类型是否存在  
  if(method.isAnnotationPresent(MyAnnotation.class)){
   method.invoke(test, new Object[]{});
   
   //AnnotatedElement接口中的方法getAnnotation(),获取传入注解类型的注解  
   MyAnnotation myAnnotation=method.getAnnotation(MyAnnotation.class);
   
   String hello=myAnnotation.hello();
   String world=myAnnotation.world();
   System.out.println("hello:"+hello+"\t world:"+world);
  }
  System.out.println("------------------------------------------------------");
  //@Retention(RetentionPolicy.RUNTIME)只有Runtime级别才能被反射读取出来
  Annotation[] annotations=method.getAnnotations();
  for (Annotation a:annotations) {
   System.out.println(a.annotationType().getName());
  }
 }
}
/**
 * @MyAnnotation @MyAnnotation2 @Deprecated  @SuppressWarnings
 * 四个注解,俩个自己写的,一个级别为RUNTIME,一个为CLASS  另外俩个系统的不知道
 * 使用反射来获取MyAnnotation中的属性的值
 * 获取Retation级别为Runtime的注解
 */ 


运行结果:
this is a method
hello:not default world:world
------------------------------------------------------
java.lang.Deprecated
day104_reflect_Annotation.MyAnnotation


我的理解是感觉没啥用处啊。 使用反射能取得注释的值,但是这个有啥用呢? 


下面来使用Junit的注释,参照 大苞米博客  
public class Calculate {
	public int add(int a,int b){
		return a+b;
	}
	
	public int divide(int a,int b) throws Exception{
		if(0==b){
			throw new Exception("除数不能为0");
		}
		return a/b;
	}
}

import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class CalulateTest {
	
	private Calculate calculate;
	
	@Before
	public void before()throws Exception{
		calculate=new Calculate();
		System.out.println("----------before()----------------");
	}
	
	@After
	public void after()throws Exception{
		System.out.println("----------after()----------------");
	}
	
	@Test
	public void addTest()throws Exception{
		System.out.println("do add test");
		int result=calculate.add(12, 2);
		assertEquals(14,result);
	}
	
	@Test(expected=Exception.class)
	public void div() throws Exception{
		System.out.println("do divide test");
		calculate.divide(8, 0);
	}
}


运行结果: 
----------before()----------------
do add test
----------after()----------------
----------before()----------------
do divide test
----------after()----------------


下面来模仿,使用自己的注释
首先需要三个注释After,Before,Test

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Before {}


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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface After {}


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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
	Class<? extends Object> expected() default String.class;
}


工具类Calculate.java
public class Calculate {
	public int add(int a,int b){
		return a+b;
	}
	
	public int divide(int a,int b) throws Exception{
		if(0==b){
			throw new Exception("除数不能为0");
		}
		return a/b;
	}
}


方法类 MyCalulateTest.java

import day104_reflect_JunitAnnotation2.Calculate;
import static day104_reflect_JunitAnnotation2.MyJUnit.*;

public class MyCalulateTest {
	
	private Calculate calculate;
	
	@Before
	public void before()throws Exception{
		calculate=new Calculate();
		System.out.println("----------before()----------------");
	}
	
	@After
	public void after()throws Exception{
		System.out.println("----------after()----------------");
	}
	
	@Test
	public void addTest()throws Exception{
		System.out.println("do add test");
		int result=calculate.add(12, 2);
		assertEquals(14,result);
	}
	
	@Test 	         
	public void div() throws Exception{
		System.out.println("do divide test");
		calculate.divide(8, 0);  //这里肯定会抛出异常
	}
}


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class MyJUnit {
	private List<Method> beforeMethod;
	private List<Method> afterMethod;
	private List<Method> testMethod;
	private static List<Exception> exceptions;

	private Object object;
	private Class<?> testClass;

	/**
	 * 构造方法初始化,获取三个方法集合
	 * 
	 * @param testName
	 */
	public MyJUnit(String testName) {
		super();
		try {
			beforeMethod = new ArrayList<Method>();
			afterMethod = new ArrayList<Method>();
			testMethod = new ArrayList<Method>();
			exceptions = new ArrayList<Exception>();

			testClass = Class.forName(testName);
			object = testClass.newInstance();

			getAllMethods();

		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	private void getAllMethods() {
		Method[] method = testClass.getMethods();
		for (Method m : method) {
			if (m.isAnnotationPresent(Before.class)) {
				beforeMethod.add(m);
			}
			if (m.isAnnotationPresent(After.class)) {
				afterMethod.add(m);
			}
			if (m.isAnnotationPresent(Test.class)) {
				testMethod.add(m);
			}
		}
	}

	/**
	 * 
	 */
	public void run() {

		for (Method m : testMethod) {
			runTest(m);
		}
		if (exceptions.size() == 0) {
			System.out.println("通过测试");
		} else {
			for (Exception e : exceptions) {
				System.out.println("测试不通过,错误为");
				e.printStackTrace();
			}
		}
	}

	private void runTest(Method m) {
		try {
			runBefores(); // 先运行before
			runTestMethod(m);
			runAfters(); // 最后运行after
		} catch (Exception e) {
			e.getMessage();
			throw new RuntimeException(
					"test should never throw an exception to this level");
		}

	}

	private void runBefores() throws Exception {
		for (Method m : beforeMethod) {
			m.invoke(object, new Object[] {});
		}
	}

	private void runAfters() throws Exception {
		for (Method m : afterMethod) {
			m.invoke(object, new Object[] {});
		}

	}

	/*
	 * 运行方法,如果有异常,则添加异常进入exceptions集合中去
	 */
	private void runTestMethod(Method m) throws Exception {

		try {
			Test testAnnotation = m.getAnnotation(Test.class);
			m.invoke(object);
		} catch (Exception e) {  // 如果测试不通过
			addExceptions(e);
		}
	}

	private static void addExceptions(Exception e) {
		exceptions.add(e);
	}

	static public void assertEquals(Object obj, Object actual) {
		if (obj.equals(actual)) {
			return;
		} else {
			addExceptions(new Exception("预期值与实际值不相等"));
		}
	}
}







测试类: 
public class TestFinal {
 
	public static void main(String[] args) {
		 	MyJUnit myJUnit=new MyJUnit("day104_reflect_JunitAnnotation2.MyCalulateTest");
		 	myJUnit.run();
	}
}


结果:
----------before()----------------
do add test
----------after()----------------
----------before()----------------
do divide test
----------after()----------------
测试不通过,错误为
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at day104_reflect_JunitAnnotation2.MyJUnit.runTestMethod(MyJUnit.java:106)
at day104_reflect_JunitAnnotation2.MyJUnit.runTest(MyJUnit.java:76)
at day104_reflect_JunitAnnotation2.MyJUnit.run(MyJUnit.java:61)
at day104_reflect_JunitAnnotation2.TestFinal.main(TestFinal.java:7)
Caused by: java.lang.Exception: 除数不能为0
at day104_reflect_JunitAnnotation2.Calculate.divide(Calculate.java:10)
at day104_reflect_JunitAnnotation2.MyCalulateTest.div(MyCalulateTest.java:31)
... 8 more




参照博客: 

http://blog.youkuaiyun.com/a396901990/article/category/2302221


我是菜鸟,我在路上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值