-- Start
简介
注解有点像修饰符,它可以加在方法、类、参数、包、域等前面提供一些附加信息。之后某些工具就可以通过反射来获得这些注解,从而做一些特殊处理。所以如果你还不熟悉反射,请先学习反射。
元注解
所谓元注解指的是定义注解的注解,它们包含在 java.lang.annotation 包中,包含如下元注解。
Documented | 指示被修饰的注解包含在javadoc生成的文档中。 |
Inherited | 指示被修饰的注解应用一个类时,该注解可以被它的子类继承。 |
Native | 指示当被修饰的注解修饰一个字段时,该字段可能是一个本地值。 |
Repeatable | 指示被修饰的注解可以重复修饰一个类,字段等 |
Retention | 指示被修饰的注解可以保留多长时间。 |
Target | 指示被修饰的注解可以修饰哪些属性。如:方法,字段等 |
预定义注解
Java 预定义了如下的注解,它们位于 java.lang 包中。
@Deprecated | 表示被修饰的属性不在推荐使用 |
@Override | 用来告诉编译器该属性继承自父类 |
@SuppressWarnings | 用来告诉编译器忽略指定的警告 |
自定义注解
下面的代码定义了一个名字是 ParaAnnotation 的注解,用@interface 关键字定义注解,该注解定义了 name 属性,格式有点像方法定义。
1. @Target({ ElementType.PARAMETER } 表示该注解用来修饰参数。
2. @Retention(RetentionPolicy.RUNTIME) 表示该注解可以再运行时使用。
package shangbo.junit;
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.PARAMETER })
public @interface ParaAnnotation {
String name() default "";
}
使用注解
如果定义了注解而没有工具使用它,那么该注解没有任何意义。下面的例子演示了一个用注解自动测试代码的例子。
1. 被测试类
package shangbo.junit;
public class StringUtils {
public String trimToEmpty(@ParaAnnotation(name = "trimToEmpty.input") String str) {
if (str == null) {
return "";
}
return str.trim();
}
public String trimToNull(@ParaAnnotation(name = "trimToNull.input") String str) {
if (str == null) {
return null;
}
str = str.trim();
if (str.equals("")) {
return null;
}
return str;
}
}
2. 测试类
package shangbo.junit;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.HashMap;
import java.util.Map;
public class Test {
// 此处代码应该配置在 XML 中
private static Map<String, String> parasMap = new HashMap<String, String>();
static {
parasMap.put("trimToEmpty.input", "test trimToEmpty");
parasMap.put("trimToNull.input", "test trimToNull");
}
@SuppressWarnings("rawtypes")
public static void main(String[] args) throws Exception {
// 要测试的类,此处应该通过参数传递
Class testClass = StringUtils.class;
// 通过反射创建对象
Object testObject = getInstance(testClass);
// 通过反射调用该类的所有方法
for (Method m : testClass.getDeclaredMethods()) {
Object returnValue = m.invoke(testObject, getParameterValues(m.getParameters()));
System.out.println(returnValue);
}
}
@SuppressWarnings("rawtypes")
private static Object getInstance(Class c) throws Exception {
// 得到构造方法
Constructor constructor = getConstructor(c);
// 得到构造方法的所有参数值
Object[] paras = getParameterValues(constructor.getParameters());
// 创建对象并返回
return constructor.newInstance(paras);
}
@SuppressWarnings("rawtypes")
private static Constructor getConstructor(Class c) {
// 得到所有构造方法
Constructor[] constructors = c.getDeclaredConstructors();
// 返回第一个构造方法
return constructors[0];
}
private static Object[] getParameterValues(Parameter[] paras) throws Exception {
if(paras == null || paras.length == 0) {
return null;
}
//
Object[] paraValues = new Object[paras.length];
for (int i = 0; i < paras.length; i++) {
paraValues[i] = getParameterValue(paras[i]);
}
return paraValues;
}
private static Object getParameterValue(Parameter para) throws Exception{
// 得到该参数的 ParaAnnotation 注解
ParaAnnotation parameterAnnotation = para.getAnnotation(ParaAnnotation.class);
if(parameterAnnotation == null) {
throw new Exception("No ParaAnnotation found for this Parameter");
}
// 根据注解得到参数值
Object parameterValue = parasMap.get(parameterAnnotation.name());
if(parameterValue == null) {
throw new Exception("Not found the value by name " + parameterAnnotation.name());
}
return parameterValue;
}
}
---更多参见:Java 精萃
-- 声 明:转载请注明出处
-- Last Updated on 2014-08-23
-- Written by ShangBo on 2014-08-22
-- End