Java注解总结(一)
Java注解总结(一)
什么是注解
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。
说白了注解就是定义在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。这里的注释是给机器看的而不是给人看的。
那么如何定义一个注解
定义注解类不能使用class、enum,也不能使用interface,而是使用@interface。
public @interface MyAnnotation{}
1. 使用注解
注解可以作用在:类(接口或枚举)、属性、方法、构造器、包、参数、局部变量
具体代码如下
@MyAnnotation
public class Person {
private static final String TAG = Person.class.getSimpleName();
@MyAnnotation
private String name;
@MyAnnotation
private int age;
@MyAnnotation
public Person() {
}
@MyAnnotation
public Person(@MyAnnotation String name, @MyAnnotation int age)
{
this.name = name;
this.age = age;
}
@MyAnnotation
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public void setName(String name)
{
this.name = name;
}
public void setAge(int age)
{
this.age = age;
}
public void test()
{
@MyAnnotation
String test = "我是测试数据";
Log.d(TAG, test);
}
}
2. 注解中的属性(其实这里叫属性更加简单明了一点 --- 设置属性的值获取属性的值)
- 定义注解时也可以定义属性
具体代码如下,还是刚才的例子。
public @interface MyAnnotation {
String name() default "张三";
int age() default 18;
String[] clothes();
}
定义一个注解的属性时候可以有默认值,可以没有默认值。如果有指定默认值,在使用注解时,可以不指定属性的值。没有的话就必须给注解属性赋值。
定义属性类型可以是
- 所有基本类型(int,float,boolean,byte,double,char,long,short)
- String
- Class
- enum
- Annotation
- 上述类型的数组
- 定义注解时也可以定义属性
@MyAnnotation(name = "张三", age = 18, clothesColor = {"红色", "蓝色"})
public class Person {
......
}
在定义注解和使用时应当注意
- 注的属性后面要有一对圆括号,而且圆括号内不能给出东西。就像是无参的方法一样;
- 数组的属性默认值:string[] clothesColor() default {"红色","蓝色","绿色"},这里不能使用new string[]{"红色","蓝色","绿色"},使用注解时,在给数组属性赋值时的格式:@MyAnnotation(clothesColor = {"红色", "蓝色"});
元注解
上述定义的注解时可以在类(接口或枚举)、属性、方法、构造器、包、参数、局部变量上使用的,那么如何限定自定义注解的作用目标呢和和使用范围?那么就应使用元注解。相信元注解的作用都很清楚了,就是用来修饰自定义注解的,简称-注解的注解。
1. 元注解都有哪些?
-
@Retention : 指定注解信息在哪个阶段存在Source Class RuntimeRetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略
RetentionPolicy.CLASS:这种类型的Annotations编译时被保 留,在class文件中存在,但JVM将会忽略
RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以 他们能在 运行时被JVM或其他使用反射机制的代码所读取和使用. -
@Target : 指定注解修饰目标对象类型TYPE 类、接口FIELD 成员变量METHOD 方法
-
@Documented :使用该元注解修饰,该注解的信息可以生成到javadoc 文档中
-
@Inherited :如果一个注解使用该元注解修改,应用注解目标类的子类都会自动继承该注解
--以上四种类型元注摘自网络
Target注解
在定义注解时可以限制注解的作用目标!例如让注解只能作用在类和方法上。这需要使用元注解:@Target。该注解有一个属性value,类型为ElementType[],它是枚举类型。具体源码如下:
public enum ElementType {
//类、接口(包括注解类型)或enum声明
TYPE,
//字段(域)声明,包括enum实例
FIELD,
//方法声明
METHOD,
//于参数声明
PARAMETER,
//构造函数声明
CONSTRUCTOR,
//局部变量声明
LOCAL_VARIABLE,
//注解声明(应用于另一个注解上)
ANNOTATION_TYPE,
//包声明
PACKAGE,
//类型参数声明(1.8新加入)
TYPE_PARAMETER,
//类型使用声明(1.8新加入)
TYPE_USE
}
例如将MyAnnotation注解作用在方法和字段上
@Target(value = {FIELD,METHOD})
public @interface MyAnnotation {
.....
}
那么现在如果要把MyAnnotation定义在类上呢,那是不存在的。编译器会报错,只能在你指定的作用目标上。
public class Person {
@MyAnnotation(name = "张三")
private String name;
@MyAnnotation(name = "张三")
public String getName() {
return name;
}
......
}
@Inherited
此注解的作用不是注解继承,而是当一个自定义注解应用了此注解,那么子类对象就可以通过getAnnotations()获取父类被修饰的注解。
@Inherited
@Target(value = {FIELD,METHOD,TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String name() ;
int age() default 18;
String[] clothesColor() default {"红色","蓝色"};
}
@MyAnnotation(name = "李四",age = 20,clothesColor = {"紫色"})
public class Person {
......
}
public class ManPerson extends Person {
}
//测试
Person person = new ManPerson();
Log.e(TAG + "--Inherited注解:", Arrays.toString(person.getClass().getAnnotations()));
//结果
MainActivity--@Inherited注解: [@com.example.annotationdemo.annotation.MyAnnotation(age=20, clothesColor=[紫色], name=李四)]
通过反射来读取注解
Java在java.lang.reflect 反射包下新增了AnnotatedElement接口,它主要用于表示目前正在 JVM 中运行的程序中已使用注解的元素,通过该接口提供的方法可以利用反射技术地读取注解的信息
返回值 | 方法名称 | 说明 |
---|---|---|
Annotation | getAnnotation(Class<A> annotationClass) | 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。 |
Annotation[] | getAnnotations() | 返回此元素上存在的所有注解,包括从父类继承的 |
boolean | isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。 |
Annotation[] | getDeclaredAnnotations() | 返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。。 |
AnnotatedElement中相关的API方法
返回值 | 方法名称 | 说明 |
---|---|---|
Annotation | getAnnotation(Class<A> annotationClass) | 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。 |
Annotation[] | getAnnotations() | 返回此元素上存在的所有注解,包括从父类继承的 |
boolean | isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。 |
Annotation[] | getDeclaredAnnotations() | 返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。。 |
使用
@Inherited
@Target(value = {FIELD}) //只能作用在类中字段上
@Retention(RetentionPolicy.RUNTIME)//运行时被JVM或其他使用反射机制的代码所读取和使用.
public @interface MyAnnotation {
String name() default "";
}
public class Person {
@MyAnnotation(name = "张三")
public String name;
}
//测试
Class<Person> personClass = Person.class;
//获取该类中所有字段
try {
Field namef = personClass.getDeclaredField("name");
boolean annotationPresentName = namef.isAnnotationPresent(MyAnnotation.class);
//如果存在此注解
if (annotationPresentName) {
//获取此注解
MyAnnotation annotation = namef.getAnnotation(MyAnnotation.class);
//打印注解的值
Log.e(TAG + "姓名", annotation.name());
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
//结果
MainActivity姓名: 张三
同理如果注解在类上可以用Class<T>.getAnnotation(ClassannotationClass)获取指定类型的注解。
Constructor,Method亦是如此。