程序员每日一篇Java程序员技术栈

Java中的注解

2018-08-19  本文已影响17人  sixleaves

1. 注解

注解是JDK5.0才开始引入的技术.

1.1 什么是注解

以下引用维基百科的解释,看不懂也没事,我会做进一步解释。
Java的注解是一种声明元数据的语法, 所谓的元数据.我在前面的文章有做过解释,即是用来描述数据的数据.

In the Java computer programming language, an annotation is a form of syntactic metadata that can be added to Java source code.[1] Classes, methods, variables, parameters and packages may be annotated. Like Javadoc tags, Java annotations can be read from source files. Unlike Javadoc tags, Java annotations can also be embedded in and read from class files generated by the compiler. This allows annotations to be retained by Java VM at run-timeand read via reflection.[2] It is possible to create meta-annotations out of the existing ones in Java.[3]

1.2 注解的语法

通过上面的介绍,我们可以推断注解主要是用在为java中的各种类型提供元数据, 并结合反射技术, 在运行时进行读取。我们先来了解下注解的语法, 写个最简单的注解.

语法

注解的语法和接口的语法十分类似。它们最显著的不同在于, 注解类型的关键字是@interface, 其次注解是使用方法类声明元素.注解中声明的一个方法表示这个注解类拥有的这个元素和其对应的类型。如下


[public | 缺省] @interface 注解名() {
         返回类型  元素名或者说是属性名() default 默认值;
}

最简单的注解

package com.sweetcs.study.annotation;

public @interface MyAnnotation {
    
}

测试下注解可以加入的位置,如下代码.直接给包贴上注解是会报错的.其他测试都没有问题, 在实际中在包上贴注解也不是很常用,后面在进行研究.

//@MyAnnotation
package com.sweetcs.study.annotation;

@MyAnnotation
public class TestAnnaotation {
    
    @MyAnnotation
    public void myPrint(@MyAnnotation int a, @MyAnnotation Object b) {
        
    }
    
    public static void main(String[] args) {
        @MyAnnotation
        String name = "test";
        System.out.println(name);
        
    }
}

尝试了注解的最简单的结构。同时我们也尝试了在类上贴上注解、在方法上贴上注解、在参数上贴上注解、在变量上贴上注解.那么它们有什么作用呢? 我们以Java中内建的常用三个注解来举例。

1.3 Java内建的三个注解

    @Test
    public void testBuildInAnnotation() {
        
        Date date = new Date();
        @SuppressWarnings({ "deprecation", "unused" })
        int year = date.getYear();
        
    }
    @Deprecated
    public int getYear() {
        return normalize().getYear() - 1900;
    }

上面代码即使Date类中的getYear

以上三个注解在java的经常的使用, 我们打开@Override和@注解,看起内部的定义的。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

元注解

public enum ElementType {
    TYPE,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,
    TYPE_PARAMETER,
    TYPE_USE
}
public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

我们开发中最常用的是前两个,也是必不可少的。

1.4 自定义注解

接扫了注解的定义语法, 描述注解的元注解.我们可以自己进行自定义注解了.

自定义步骤

  1. 声明注解类型和其方法.
  2. 使用元注解@Retation和@Target说明注解的使用范围和注解的生命周期
package com.sweetcs.study.annotation;

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

@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER})
public @interface MyCustomerAnnotation {

    String name() default "SweetCS";
    
    String[] sons();
}
    @Test
    public void testCustomerAnnotation() {
        
        @MyCustomerAnnotation(name="test", sons={"son1", "son2"})
        int a = 1;
        
    }

1.5 注解的本质和便捷写法

注解的本质

我们写的注解底层其实是会在编译阶段自动的编译成继承java.lang.annotation.Annotation接口的接口.但是不允许我们显示的继承自该接口.

注解简便写法

阅读底层注解的实现代码,我们会发现其方法名无论返回类型是啥。方法名都清一色的命名为value.这是因为Java的注解中规定.只要方法名为value, 在使用注解的时候, 不同指定注解的元素名.如下代码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

我们在使用@Retention的使用不需要指定元素名.默认就是value

1.6 获取注解信息

image.png

下面代码, 使用反射来获取Father类的Class对象, 然后获取其上的注解

    @Test
    public void testCustomerAnnotation() {
        
        // 获取Father类上的注解
        MyCustomerAnnotation annOfFatherClass = Father.class.getAnnotation(MyCustomerAnnotation.class);
        System.out.println(annOfFatherClass);
        System.out.println(annOfFatherClass.name() + "  " + Arrays.toString(annOfFatherClass.sons()));
    
    }

运行输出

后续

注解使用场景主要是反射结合使用. 因为反射结合使用, 所以注解使用的最多的是在类上和类中的成员上.后续我会分享基于注解和反射来动态的创建表.可以大大提高我们的编程体验, 让我们无需去关注建表语句.

上一篇下一篇

猜你喜欢

热点阅读