您的位置:首页 > 编程语言 > Java开发

java 学习自定义注解Annotation

2017-11-23 18:47 232 查看
Annotation 注解相信大家平时经常用到,比如常见的有@Override  @Deprecated  @SuppressWarnings

还有很多第三方框架也用到了自定义注解,以前一直觉得很神奇,其实学习自定义才发现还是很简单的嘛

什么是注解?

由于不擅言辞,我就直接引用大神的博客介绍了,以下是大神博客地址
http://blog.csdn.net/hai_qing_xu_kong/article/details/51779695    点击打开链接

注解是一种元数据, 可以添加到java代码中. 类、方法、变量、参数、包都可以被注解,注解对注解的代码没有直接影响

首先了解下元注解,

元注解就是用来定义注解的注解.其作用就是定义注解的作用范围, 使用在什么元素上等等, 

元注解共有四种@Retention, @Target, @Inherited, @Documented

@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:在运行时有效(即运行时保留)

@Documented:

  @Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

@Inherited:

  @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。 

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。 

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

其中, @Retention是定义保留策略, 直接决定了我们用何种方式解析. SOUCE级别的注解是用来标记的, 比如Override, SuppressWarnings. 我们真正使用的类型是CLASS(编译时)和RUNTIME(运行时)

自定义注解:

  使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。 

以上很大一篇都是详细介绍注解的,现在直接来自定义吧



我总共创建了4个类,Person 和 PersonAttr 就是定义的注解,LaoFuzi是使用注解的类,MainActivity是运行效果的类

先看下Person

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

/**
* 自定义用于方法描述的注解
* Created by Alex on 2017/11/23.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Person {

boolean beautiful() default false;

int age() default 0;

String name() default "Alex";
}


这个注解用于方法的描述,所以用@Target({ElementType.METHOD}),保存时机一般都是用@Target({ElementType.METHOD}),因为我们绝大部分都是需要运行时用

内部定义了几个方法,后面的返回的默认值,返回值必须是可以定义常量的类型

再看下PersonAttr

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

/**
* 自定义用于成员变量描述的注解
* Created by Alex on 2017/11/23.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface PersonAttr {

String value();

}


这个注解用于描述成员变量,比如很多请求框架都用到,便于解析字段,跟Person差不多,只是@Target({ElementType.FIELD})这里改变了下,当然还可以定义其他类型

LaoFuzi,使用刚才定义的注解,方法和成员变量都用到了

public class LaoFuzi {

@PersonAttr("name")
public String name;

@Person(beautiful = false, age = 28, name = "老夫子")
public void printPersonInfo() {

}
}


最后看下效果

private static final String TAG = MainActivity.class.getSimpleName();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Method[] methods = LaoFuzi.class.getDeclaredMethods();
for (Method method: methods) {
Person person = method.getAnnotation(Person.class);
if (person != null) {
Log.d(TAG, person.name() + " "  + person.age() + " " + person.beautiful());
}
}

Field[] fields = LaoFuzi.class.getDeclaredFields();
for (Field field : fields) {
PersonAttr personAttr = field.getAnnotation(PersonAttr.class);
if (personAttr != null) {
Log.d(TAG, personAttr.value());
}
}

}


打印结果:

11-23 15:41:31.617 9793-9793/android.example.com.customannotationdemo D/MainActivity: 老夫子 28 false

11-23 15:41:31.617 9793-9793/android.example.com.customannotationdemo D/MainActivity: name

demo 地址
http://download.csdn.net/download/msn465780/10130482  点击打开链接

到这里已经完成了自定义注解,是不是很简单啊,又可以愉快的玩耍了
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息