Java中的注解

2017-03-22  本文已影响0人  红烧排骨饭

什么是注解

Annotations, a form of metadata, provide data about a program that is not part of the program itself. Annotations have no direct effect on the operation of the code they annotate.

注解是一种元数据,提供代码的信息,但不是代码的一部分,对被注解的代码的运行没有影响。

这里提到的元数据是描述数据的数据,结合实例来说明:

<string name="app_name">AnnotionDemo</string>

这里的"app_name"就是描述数据"AnnotionDemo"的数据。

public class MainActivity extends AppCompatActivity {

    @InjectView(R.id.tv)
    TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Views.inject(this);  // 利用反射获取注解的信息
    }
}

注解的作用

Annotations have a number of uses, among them:

注解是如何工作的?

注解仅仅是元数据,和业务逻辑无关,所以当你查看注解类时,发现里面没有任何逻辑处理

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {

    int value();
}

如果注解不包含业务逻辑处理,必然有人来实现这些逻辑。注解的逻辑实现是元数据的用户来处理的,注解值提供信息,由注解的用户读取这些信息并实现必要的逻辑。

当使用java中的注解时(比如@Override、@Deprecated、@SuppressWarnings)JVM就是用户。

如果是自定义的注解,它的用户是每个使用注解的类,在被注解的类中通过反射来获取注注解的信息。

比如使用注解简化 findViewById 的操作

public class MainActivity extends AppCompatActivity {

    @InjectView(R.id.tv)
    TextView mTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Views.inject(this);  // 利用反射获取注解的信息
    }
}

Views.inject(this) 的实现

public class Views {

    public static void inject(Activity activity) {
        Class<? extends Activity> activityClass = activity.getClass();
        Field[] fields = activityClass.getDeclaredFields();
        for (Field field : fields) {
            InjectView injectViewAnnotation = field.getAnnotation(InjectView.class);
            if (injectViewAnnotation != null) {
                View view = activity.findViewById(injectViewAnnotation.value());
                try {
                    field.setAccessible(true);
                    field.set(activity, view);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

注解的元注解

通过阅读注解类的源码可以发现,任何一个注解类都有如下特征:

@Target

@Target annotation marks another annotation to restrict what kind of Java elements the annotation can be applied to.

@Target 用来约束该注解的使用范围。主要有几个

ElementType.ANNOTATION_TYPE can be applied to an annotation type.
ElementType.CONSTRUCTOR can be applied to a constructor.
ElementType.FIELD can be applied to a field or property.
ElementType.LOCAL_VARIABLE can be applied to a local variable.
ElementType.METHOD can be applied to a method-level annotation.
ElementType.PACKAGE can be applied to a package declaration.
ElementType.PARAMETER can be applied to the parameters of a method.
ElementType.TYPE can be applied to any element of a class.

@Retention

@Retention @Retention annotation specifies how the marked annotation is stored:

表示需要在什么级别保存该注解信息,用于描述注解的生命周期,即被描述的注解在什么范围内有效

@Documented

@Documented annotation indicates that whenever the specified annotation is used those elements should be documented using the Javadoc tool. (By default, annotations are not included in Javadoc.)

可以用来生成 Javadoc 文档

@Inherited

@Inherited annotation indicates that the annotation type can be inherited from the super class. (This is not true by default.) When the user queries the annotation type and the class has no annotation for this type, the class' superclass is queried for the annotation type. This annotation applies only to class declarations.

用于描述某个被标注的类型是可被继承的

自定义注解

格式

元注解
public @interface 注解名 {
    定义体;
}

特别说明

  1. 注解类中的方法只能用 public 或者默认这两个访问权修饰,不写public就是默认
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
    public enum Color{ BULE,RED,GREEN};
    Color fruitColor() default Color.GREEN;
}
···

2. 如果注解类中只有一个成员,最好把方法名设置为"value",比如

```java
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
  1. 注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为 null。因此, 使用空字符串或 0 作为默认值是一种常用的做法。

实战

自定义注解 ToDo.java

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
    public enum Priority {LOW, MEDIUM, HIGH}
    public enum Status {STARTED, NOT_STARTED}    
    String author() default "Yash";
    Priority priority() default Priority.LOW;
    Status status() default Status.NOT_STARTED;
}

使用注解的类 BusinessLogic

public class BusinessLogic {
    public BusinessLogic() {
        super();
    }

    public void compltedMethod() {
        System.out.println("This method is complete");
    }    

    @Todo(priority = Todo.Priority.HIGH)
    public void notYetStartedMethod() {
        // No Code Written yet
    }

    @Todo(priority = Todo.Priority.MEDIUM, author = "Uday", status = Todo.Status.STARTED)
    public void incompleteMethod1() {
        //Some business logic is written
        //But its not complete yet
    }

    @Todo(priority = Todo.Priority.LOW, status = Todo.Status.STARTED )
    public void incompleteMethod2() {
        //Some business logic is written
        //But its not complete yet
    }
}

注解的用户 TodoReport

public class TodoReport {
    public TodoReport() {
        super();
    }

    public static void main(String[] args) {
        getTodoReportForBusinessLogic();
    }

    /**
     * 解析使用注解的类,获取通过注解设置的属性
     */
    private static void getTodoReportForBusinessLogic() {
        Class businessLogicClass = BusinessLogic.class;
        for(Method method : businessLogicClass.getMethods()) {
            Todo todoAnnotation = (Todo)method.getAnnotation(Todo.class);
            if(todoAnnotation != null) {
                System.out.println(" Method Name : " + method.getName());
                System.out.println(" Author : " + todoAnnotation.author());
                System.out.println(" Priority : " + todoAnnotation.priority());
                System.out.println(" Status : " + todoAnnotation.status());
                System.out.println(" --------------------------- ");
            }
        }
    }
}

运行结果

Method Name : notYetStartedMethd
Author : Yash
Priority : HIGH
Status : NOT_STARTED
--------------------------
Method Name : incompleteMethod2
Author : Yash
Priority : LOW
Status : STARTED
--------------------------
Method Name : incompleteMethd1
Author : Uday
Priority : MIDUM
Status : STARTED
--------------------------

总结

参考来源

上一篇 下一篇

猜你喜欢

热点阅读