注解介绍
- 1.5开始引入
- 注解可以理解为一种描述数据的数据,或者可以称为一种描述元数据的方法。
- java提供的默认注解:@Override,@Deprecated。
- 注解仅仅是元数据,和业务逻辑无关
- 定义方法在 java.lang.annotation包中
元注解
java提供4中元注解来定义我们的注解
1. @Target,
2. @Retention,
3. @Documented,
4. @Inherited
1. @Target,
@Target说明了Annotation所修饰的对象范围,即用于描述注解的使用范围
1. CONSTRUCTOR:用于描述构造器
2. FIELD:用于描述域
3. LOCAL_VARIABLE:用于描述局部变量
4. METHOD:用于描述方法
5. PACKAGE:用于描述包
6. PARAMETER:用于描述参数
7. TYPE:用于描述类、接口(包括注解类型) 或enum声明
8. ANNOTATION_TYPE:适用于annotation类型,声明注解类型
9. TYPE_PARAMETER:1.8版本
10. TYPE_USE: 1.8版本
TYPE_PARAMETER和TYPE_USE扩展了泛型使用场景,包括泛型、超类和接口实现、甚至是方法的Exception声明。
2. @Retention
- SOURCE:在源文件中有效(即源文件保留),在编译阶段丢弃。注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。比如:@Override
2.CLASS:在class文件中有效(即class保留)。在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
3.RUNTIME:在运行时有效(即运行时保留)。 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息比。如:@Deprecated。比如Srping中的@Autowired,@ResponseBody等都属于这一类。
表示需要在什么级别保存该注释信息,用于描述注解的生命周期
3. @Inherited
介绍:
元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
使用此注解声明出来的自定义注解,在使用此自定义注解时,如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。这里一定要记住,使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。
4. @Documented
一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。
表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的。
示例:
在某个方法上增加了有Documented注解的元注解,则javadoc命令生成xxx.html文件中。可以看到该注解。
注解元素
注解类中定义的元素称为注解元素,注解元素可用的类型如下:
- 所有基本数据类型(int,float,boolean,byte,double,char,long,short)
- String类型
- Class类型
- enum类型
- Annotation类型
- 以上所有类型的数组
实际使用注意问题
1. 使用注解不使用名字时,赋值规则,
如果注解只有一个属性,那么肯定是赋值给该属性。
如果注解有多个属性,而且前提是这多个属性都有默认值,那么你不写注解名赋值,会赋值给名字为“value”这属性。
如果注解有多个属性,其中有没有设置默认值的属性,那么当你不写属性名进行赋值的时候,是会报错的。
2. 若注解中定义了多个注解元素,除非注解元素使用的default。否则在使用该注解时,都需要赋值。
示例
1. 变量上的注解
1.1 注解定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnno {
public String fileName() default "defaultFileName";
public int value();
}
1.2 使用
public class MyAnno {
@FieldAnno(111)
private String myStr;
...
}
1.3 调用
/**
* 根据字段名
*/
public static void getFieldAnno() {
try {
Field myfiel = MyAnno.class.getDeclaredField("myStr");
// myfiel.setAccessible(true);
FieldAnno fieldAnno = myfiel.getAnnotation(FieldAnno.class);
if (fieldAnno != null) {
System.out.println("----getFieldAnno----");
System.out.println(fieldAnno.fileName());
System.out.println(fieldAnno.value());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
/**
* 搜索所有字段
*/
public static void getFieldAnno2() {
Field[] fields = MyAnno.class.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(FieldAnno.class)) {
FieldAnno fieldAnno = field.getAnnotation(FieldAnno.class);
System.out.println("----getFieldAnno2----");
System.out.println(fieldAnno.fileName());
System.out.println(fieldAnno.value());
}
}
}
2. 一般方法上的注解
2.1 定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnno {
String methodNamett();
}
2.2 使用
@MethodAnno(methodNamett = "mycustomerMethod")
private static void myMethod(){
}
2.3 调用
/**
* 根据方法名获取
*/
public static void getMethodAnno() {
try {
Method myMethod = MyAnno.class.getDeclaredMethod("myMethod", MyAnno.class.getClasses());
MethodAnno methodAnno = myMethod.getDeclaredAnnotation(MethodAnno.class);
System.out.println(methodAnno.methodNamett());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* 查询所有方法
*/
public static void getMethodAnno2() {
Method[] myMethods = MyAnno.class.getMethods();
for (Method method : myMethods) {
if(method.isAnnotationPresent(MethodAnno.class)){
MethodAnno methodAnno = method.getDeclaredAnnotation(MethodAnno.class);
System.out.println(methodAnno.methodNamett());
}
}
}
3. 构造方法上的注解
3.1 定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface ConstructorAnno {
boolean isDefault();
}
3.2 使用
@ConstructorAnno(isDefault = true)
public MyAnno() {
}
@ConstructorAnno(isDefault = false)
public MyAnno(String name) {
}
3.3 调用
/**
* 根据指定名称获取
*/
public static void getConAnno() {
try {
Constructor defaultConstructor = MyAnno.class.getDeclaredConstructor();
ConstructorAnno constructorAnno=defaultConstructor.getDeclaredAnnotation(ConstructorAnno.class);
System.out.println(constructorAnno.isDefault());
Constructor Constructor = MyAnno.class.getDeclaredConstructor(String.class);
ConstructorAnno constructorAnno2=Constructor.getDeclaredAnnotation(ConstructorAnno.class);
System.out.println(constructorAnno2.isDefault());
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
/**
* 搜索所有构造方法
*/
public static void getConsAnno2() {
Constructor[] myConstructors = MyAnno.class.getConstructors();
for (Constructor constructor : myConstructors) {
if (constructor.isAnnotationPresent(ConstructorAnno.class)) {
ConstructorAnno constructorAnno = constructor.getDeclaredAnnotation(ConstructorAnno.class);
System.out.println(constructorAnno.isDefault());
}
}
}
4. 类上的注解
4.1 定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//可以修饰class 和inteface
public @interface TypeAnno {
String type();
}
4.2 使用
@TypeAnno(type="myTypeAnno")
public class MyAnno {
}
4.3 调用
/**
* 根据类名查询该类的
*/
public static void getTypeAnno() {
TypeAnno typeAnno = MyAnno.class.getDeclaredAnnotation(TypeAnno.class);
System.out.println(MyAnno.class.isAnnotationPresent(TypeAnno.class));
System.out.println(typeAnno.type());
}
/**
* 查询包名下所有类
*/
public static void getAnnoTypeAnno() {
String basePackage = "com.myannotation";
try {
//先找到资源
Enumeration<URL> enums = Thread.currentThread().getContextClassLoader().getResources(basePackage.replace(".", "/"));
while (enums.hasMoreElements()) {
URL uri = enums.nextElement();
if ("file".equals(uri.getProtocol())) {//是否是文件协议的文件
String dirsStr = uri.getFile();//获取文件路径
File dirsFile = new File(dirsStr);//创建File的文件夹对象
if (dirsFile.isDirectory()) {
File[] files = dirsFile.listFiles();//获取该文件夹下所有文件
for (File file : files) {
if (file.isFile()) {
String classname = basePackage + "." + file.getName();
classname = classname.substring(0, classname.length() - 6);
// System.out.println(classname);
Class clazz = Class.forName(classname);
if (clazz.isAnnotationPresent(TypeAnno.class)) {
TypeAnno typeAnno = (TypeAnno) clazz.getDeclaredAnnotation(TypeAnno.class);
System.out.println(typeAnno.type());
}
}
}
}
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
5. 局部变量的注解
public void m(int a)
@MyOwnAnnotation(some information)
int b = 5;
}
目前无法通过反射的方法来获取局部变量上的注解(https://stackoverflow.com/questions/17237813/elementtype-local-variable-annotation-type)
6. 参数上的注解
6.1 定义
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface ParamAnno {
String value() ;
}
6.2 使用
public static void meMethod(@ParamAnno("myvalue") String name1,String name2){
@LocalVariableAnno()
String tt;
}
6.3 调用
public static void getParamAnno() {
try {
Method method = MyAnno.class.getDeclaredMethod("meMethod", String.class, String.class);
Annotation[][] paramss = method.getParameterAnnotations();
for (Annotation[] parameterAnnotation : paramss) {
for (Annotation annotation : parameterAnnotation) {
if (annotation instanceof ParamAnno) {
ParamAnno param = (ParamAnno) annotation;
System.out.println(param.value());
}
}
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
7. 包注解
作用
1、为标注在包上Annotation提供便利;
2、声明包的私有类和常量;
* 3、提供包的整体注释说明
8. ANNOTATION_TYPE
待续
9. TYPE_PARAMETER和TYPE_USE
Spring中使用的注解
AliasFor
给注解起别名。
参考
https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
Java注解之Retention、Documented、Inherited介绍