Java 注解(Annotation) 的基本使用和理解

1.注解

概念:相当于标签

2.注解的类型

2.1 元注解

概念:元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面

元注解的种类

  • @Retention
  • @Documented
  • @Target
  • @Inherited
  • @Repeatable

@Retention

作用:解释/说明了注解的生命周期

取值如下:

 RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。 
 RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。 
 RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中

@Documented

作用:将注解的元素包含到javadoc文档中

@Target

作用:限定了注解作用的目标范围,包括累、方法等

取值如下

  • ElementType.PACKAGE 可以给一个包进行注解
  • ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
  • ElementType.CONSTRUCTOR  可以给构造方法进行注解
  • ElementType.FIELD 可以给属性进行注解
  • ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
  • ElementType.METHOD 可以给方法进行注解
  • ElementType.PARAMETER 可以给一个方法内的参数进行注解
  • ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Inherited

作用: 继承注解(如一个父类使用了该注解,那么它的子类没有进行其他注解的话,则会继承了父类的注解。)

    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @interface Test {}

    //父类使用了Test注解
    @Test
    public class A {

    }

    //子类没有使用其他注解,则继承了父类的注解
    public class B extends A {}

@Repeatable

作用:可重复注解,即注解的值可以同时取多个

    //1.
    //定义Person的容器注解
    @interface Persons {
        Person[]  value();
    }


    //2.
    //定义Person的注解
    //@Repeatable括号中的类是容器注解
    @Repeatable(Persons.class)
    @interface Person{
        String role() default "";
    }


    //3.
    //取多个值来修饰,即是艺术家也是厨师
    @Person(role="artist")
    @Person(role="chef")
    public class SuperMan{

    }

2.2 Java内置的注解

@Deprecated

作用:用来标记过时的元素的。

Java 注解(Annotation) 的基本使用和理解_第1张图片

@SuppressWarnings

作用:被标记的元素会阻止编译器发出的警告提醒

Java 注解(Annotation) 的基本使用和理解_第2张图片

@Override

作用:子类要复写父类中被Override修饰的方法

@SafeVarargs

作用:提醒开发者不要用参数做不安全的操作&阻止编译器产生unchecked警告

// 以下是官方例子
// 虽然编译阶段不报错,但运行时会抛出 ClassCastException 异常
// 所以该注解只是作提示作用,但是实际上还是要开发者自己处理问题
@SafeVarargs // Not actually safe!
    static void m(List... stringLists) {
    Object[] array = stringLists;
    List tmpList = Arrays.asList(42);
    array[0] = tmpList; // Semantically invalid, but compiles without warnings
    String s = stringLists[0].get(0); // Oh no, ClassCastException at runtime!
}

@FunctionalInterface

作用:表示该接口为函数式。函数式接口=具有1个方法的普通接口

问题:为什么要用额外的函数式接口标记

答案:函数式接口很容易转化为Lambda表达式

比如

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface Runnable is used
     * to create a thread, starting the thread causes the object's
     * run method to be called in that separately executing
     * thread.
     * 

* The general contract of the method run is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }

2.3 自定义注解

2.3.1 定义注解

//通过@interface定义Test注解
    public @interface Test{

    }

2.3.2 注解属性

注解的属性也叫成员变量。注解只有成员变量,没有方法

注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。

注意点:注解中定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解及它们的数组

public @interface Test{

        int id();

        String msg();

    }

我们在Test注解里定义了id和msg两个属性,在使用他们的时候我们应该进行赋值

@Test(id=5,msg = "hello")
public class AnnotationTest {

}

你也可以设置默认值

public @interface Test {

    
    int id() default 10;

    String msg() default "hello";
}

这样子id的默认值是10,msg的默认值是hello。因为有默认值所以可以在使用的时候括号里可以不填

直接@Test()

还有一种情况就是注解内只有一个属性的时,可以直接注解括号里填写一个值@Test(10)

2.3.3 获取注解

之前比喻了注解是标签,那现在获取标签然后检阅上面的内容信息。那怎么实现呢,通过反射

//判断是否应用了某注解
public boolean isAnnotationPresent(Class annotationClass) {}

//获取注解在这个元素的指定注解的对象
public  A getAnnotation(Class annotationClass) {}

//获取注解在这个元素的所有注解对象
public Annotation[] getAnnotations() {}

以下演示

注解类

@Retention(RetentionPolicy.RUNTIME)
public @interface Test {

    String name() default "hello";

    int age() default 10;
}

被注解的类

@Test(name = "class",age = 100)
public  class Person  {



    @Test(name = "hey",age = 40)
    private String name;



    @Test(name = "hi",age = 20)
    public void son(){

    }


}

类注解获取:

  Class aClass = Person.class;
        //判断是否应用了该注解
        boolean hasAnnotation = aClass.isAnnotationPresent(Test.class);
        if (hasAnnotation) {
            //拿到Annotation注解
            Annotation annotation = aClass.getAnnotation(Test.class);
            Test myAnnotation = (Test) annotation;
            //获取name以及age
            System.out.println("name: " + myAnnotation.name());
            System.out.println("value: " + myAnnotation.age());
        }

//name:class
//age:100

 

方法注解获取:

 Method method = null;
        try {
            //拿到该方法对象(son为该方法名)
            method = Person.class.getDeclaredMethod("son");
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        Annotation annotationMethod = method.getAnnotation(Test.class);
        Test myAnnotation = (Test) annotationMethod;
        System.out.println("name: " + myAnnotation.name());
        System.out.println("value: " + myAnnotation.age());

//name:hi
//age:20

变量注解获取

        Class aClass = Person.class;

        try {
            Field field=aClass.getDeclaredField("name");
            Test annotation=field.getAnnotation(Test.class);

            System.out.print(annotation.name());
            System.out.print(annotation.age());
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

//name:hey
//age:40

3.注解应用实例

JUnit

JUnit 这个是一个测试框架,典型使用方法如下:

public class ExampleUnitTest {
    @Test
    public void addition_isCorrect() throws Exception {
        assertEquals(4, 2 + 2);
    }
}

ButterKnife

ButterKnife 是 Android 开发中大名鼎鼎的 IOC 框架,它减少了大量重复的代码。

public class MainActivity extends AppCompatActivity {

    @BindView(R.id.tv_test)
    TextView mTv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.bind(this);
    }
}

还有 Degger2以及Retrofit等等

之前整理的笔记借鉴了这位大神的文章

地址 https://blog.csdn.net/briblue/article/details/73824058

你可能感兴趣的:(android,java)