Java入门篇——注解Annotation

在Java1.5以后,引入了注解,也称作元数据。作为新的特性,同时也是基础知识之一,我们应该学会使用这种用法,虽然反射会带来代码效率问题,但相比于它的优点,这种损失我们还是可以承受的。

元数据被定义为:描述数据的数据,对数据及信息资源的描述性信息。

我们可以认为注解的目的就是对数据添加的附加信息。在java源代码中添加注解,有助于减轻编写“样板”代码的负担(findViewById),更加干净易读的代码以及编译器类型检查。

注解的语法比较简单,使用一个@符号修饰代表的就是一个注解。Java 5内置的几种注解有

//当前的方法定义将覆盖超类中的方法
@Override
//代表被这个元数据修饰的元素已被废弃,使用已废弃的方法或对象编译器会发出警告
@Deprecated
//关闭不当的编译器警告信息,比如unchecked,未检查的类型等
@SuppressWarnings

自定义注解类型

使用@interface来定义注解类型

public @interface Test {
}

使用注解类型

//一般写法,比较优美
@Test
void test(){
    
}

//注解可以看做是一种修饰符,它的使用和修饰符几乎一模一样
// 不太好看,不建议
public static synchronized @Test void  test(){
    
}

上面简单定义了一个注解,但是一般我们定义的注解,还会定义一些注解的类型,Annotation有四种元注解类型,元注解专职负责注解其他的注解,详情可以看Java API里面的Annotation

# Retention 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}

# Target 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

# Documented
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

# Inherited 
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

Rentention
Rentention定义该注解在哪一个级别保留该注解信息,可选的RetentionType参数包含

// 存在于Java源文件,注解被编译器丢弃
SOURCE
// 存在于Java源文件,以及经编译器后生成的Class字节码文件,但在运行时VM不再保留注解
CLASS
// 存在于源文件、编译生成的Class字节码文件,以及保留在运行时VM中,因此可通过反射读取注解
RUNTIME

**Target **
Target表示该注解可以用于什么地方,可能使用的参数ElementType包括

// 注解类型,表示这个注解只能用于注解类型
// 比如Target,Rentention,Inherited,Documented这些元注解都是用于注解类型的
ANNOTATION_TYPE
// 构造器声明
CONSTRUCTOR
// 字段声明(包括enum实例)
FIELD
// 局部变量声明
LOCAL_VARIABLE
// 方法声明
METHOD
// 包声明
PACKAGE
// 参数声明
PARAMETER
// 类,接口(包括注解类型)或者enum声明
TYPE

Documented
当前注解的元素会被javadoc工具进行文档化,那么在查看Java API文档时可查看该注解元素。

Inherited
允许子类继承父类中的注解

注解元素
在注解中还会包含一些元素表示值,当使用Class里面的方法分析处理注解的时候,程序就可以访问这些值。在注解中定义元素就像在普通接口中定义方法,但是注解可以使用default定义元素的默认值。对于没有元素的注解,我们可以把它作为标记来使用。比如被@Test标记的方法为测试方法
注解元素可用的类型包括如下几个

基本数据类型
String
Class
enum
Annotation
以上类型的数组

对于注解里面的元素,必须有一个确定的值,不能够使用null这种未定义的值作为默认值,所以我们可以使用空对象这样的概念来解决这个问题,比如定义空字符串作为字符串为null的情况。

解析注解
在很多ORM数据库框架中都使用了注解来定义Bean类,直接使用Bean类生成数据库表。比如ORMLite。

如果不对注解进行解析的话,其实注解就没什么意义了,可以通过Annotation中提供的API来访问注解。那么先来看一下Class提供给我们的用于解析注解的结构方法

// 如果当前元素包含指定的注解类型,则返回该注解对象,如果不存在则返回null
<A extends Annotation> getAnnotation(Class<A> annotationClass)
// 返回这个元素上的所有注解
Annotation[] getAnnotations()
// 返回直接定义在这个元素上的注解
Annotation[] getDeclaredAnnotations()
// 如果当前这个元素包含指定的注解类型则返回true
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

在Android中也有通过注解实现的IOC,我们在编写程序的时候,如果xml里面有很多很多的控件,这样就需要写很多遍findViewById,不但写起来很累,而且很占空间,于是人们就想到了通过注解来减轻这样的编写“样板”代码的负担。

ViewInject注解类

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ViewInject {
    int id() default -1;
}

BaseActivity基类,使用模板方法

public abstract class BaseActivity extends Activity {
    private Context mContext;

    private void inject() {
        Class activity = getClass();
        //获取Activity内所有的字段
        Field[] fields = activity.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取指定的注解类型,如果返回null则跳过
            ViewInject viewInject = field.getAnnotation(ViewInject.class);
            if (viewInject != null) {
                // 获取指定的属性
                int value = viewInject.id();
                try {
                    // 反射获取findViewById方法
                    Method method = activity.getMethod("findViewById", int.class);
                    method.setAccessible(true);
                    // 调用该方法,因为findViewById要求是在Activity对象上的方法
                    Object object = method.invoke(mContext, value);
                    field.set(mContext, object);
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    protected abstract int requestLayout();

    protected abstract void bindView();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(requestLayout());
        mContext = this;
        inject();
        bindView();
    }
}

MainActivity实现类

public class MainActivity extends BaseActivity {
    @ViewInject(id=R.id.text)
    private TextView textView;

    @Override
    protected int requestLayout() {
        return R.layout.layout_annotation;
    }

    @Override
    protected void bindView() {
        textView.setText("1131");
    }

}

现在大致上那些retrofit,dagger,butterknife使用的注解也是基于这个原理的罢,有空去好好研究一下这几个开源框架的源码,使用注解,我们应该还需要有类加载,泛型,反射等基础知识,才能够把注解玩的飞起。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 本文章涉及代码已放到github上annotation-study 1.Annotation为何而来 What:A...
    zlcook阅读 29,119评论 15 116
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和...
    九尾喵的薛定谔阅读 3,141评论 0 2
  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李头阅读 6,390评论 4 31
  • 2017年10月23日 周一 晴天 今天霜降,气温骤降很多,已经不再处于早晚温度低的状态,下雨的时候白天也很冷涩,...
    五厘米阅读 207评论 0 0
  • 最近一切生活照旧,但和冠宇的关系好像慢慢得到缓解,很开心!那么就这样下去吧,戒骄戒躁!安静平淡的维护好这段友情,可...
    InGu阅读 185评论 0 0