Java基础_注解

理解

  • 注解就是标签

  • 这里先不引出概念

具体描述

  • 注解是在JavaSE 5.0版本引入的一个概念

注解的定义

  • 使用@interface关键字进行定义

    public @interface DemoAnnotation{
    
    }
    
    • 上述的代码创建了一个名字叫做DemoAnnotation的注解,可以理解创建了一个名字叫做DemoAnnotation的标签。

注解的应用

  • 创建一个类Demo,在类定义的地方加入 @DemoAnnotation就可以使用这个注解类了。
  • 从我们说的标签角度说 就是为Demo贴上了一个名字叫做DemoAnnotation的标签。

元注解

  • 元注解是可以注解到注解上的注解,元注解也是一种注解,但是能够用到其他注解上面。
  • 从标签的角度说,元注解也是一种标签,只不过是用来给其他标签进行解释说明的。
  • 元标签:@Retention @Documented @Target @Inherited @Repeatable
Retention

当Retention注解应用到一个注解上的时候,它解释说明了这个注解的存活时间。

有如下几种取值

  • RetentionPolicy.SOURCE 注解只在源代码阶段保留,在编译器编译的时候会被忽略。

  • RetentionPolicy.CLASS 注解只被保留到编译进行时,不会被加载到JVM中。

  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载到JVM中,所以在程序运行的时候可以拿到它们。

  • @Retention去给一张标签解释的时候,它指定了这张标签张贴的时间。

  • @Retention相当于给一张标签上面盖了一张时间戳,时间戳指明了标签张贴的时间周期

    @Retention(RetentionPolicy.RUNTIME)
    public @interface DemoAnnotation{
    
    }
    
    • 上述代码我们给DemoAnnotation注解指定了Retention注解,该注解指明了注解DemoAnnotation可以在程序运行期间获取到,生命周期很长。
@Documented
  • 这个注解和文档的注释有关,能够将注解中的元素包含到Javadoc中去。
@Target
  • Target 目标的意思
  • @Target注解指定了注解运用的地方
  • 当一个注解被@Target注解时,这个注解就被限定了运用场景。
  • 从我们标签的角度来说就是,我们给标签限定了张贴的地方了,比如这个注解是在方法上使用,类上等等

@Target有如下的取值

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

遗传、继承的意思

并不是说注解本身是可以遗传的。而是说一个超类被@Inherited注解过的注解注解了,那么如果子类没有被任何注解应用的话,那么这个子类就继承了超类的注解

  • 代码演示
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface DemoAnnotation{}

@DemoAnnotation
public class Demo{}

public class Demo1 extends Demo{}

如上述代码,@DemoAnnotation被注解@Inherited修饰,Demo被注解@DemoAnnotation所修饰,Demo1继承至Demo,Demo1没有被其他注解所修饰,那么Demo1就拥有了@DemoAnnotation的注解了

@Repeatable

Repeatable是可重复的 在Java1.8时加进来的,算是一个新特性

  • 一个人他既可以是一个程序员也是一个产品总监,也可以是一个运动员

    @interface Persons{
          Person [] values();
    }
    
    @Repeatable(Persons.class)
    @interface Person{
      String role defaule "";
    }
    
    @Person(role="coder")
    @Person(role="PM")
    @Person(role="sportsman")
    public class SuperMan{
      
    }
    
    • @Repeatable注解了 Person,而@Repeatable后面的括号中的类相当于一个容器注解
    • 所谓的容器注解就是用来存放其他注解的地方,本身也是一个注解
    • 从标签的角度来说,Persons是一张总的标签。上面贴满了Person这种类型的标签但是内容是不一样的。

注解的属性

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

注解的成员变量在注解的定义中以“无形参的方法”形式声明的

其方法名定义了该成员变量的名字,其返回值定义了成员变量的类型

  • 代码示例

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DemoAnnotation {
      //定义了两个注解属性 分别为 id和name
        int id();
    
        String name();
    }
    
    //在使用注解的时候,需要把注解属性给声明了,中间以 “,”分隔
    @DemoAnnotation(id = 3,name = "DashingQi")
    public class Demo {
    }
    
    • 在注解中定义属性时。它们的类型必须是8种基本数据类型,外加接口、类、注解以及8种基本数据类型的数组
    • 注解中声明的属性可以有默认值,声明默认值使用default关键字
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DemoAnnotation {
        int id() default 1;
    
        String name() default "ZhangQi";
    }
    
    
    • 当注解中声明的属性有默认值的时候,在使用注解的时候,可以不用声明属性值
    @DemoAnnotation()
    public class Demo {
    }
    
    • 当声明的注解没有属性的时候,使用注解可以不用写括号
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DemoAnnotation {
        
    }
    
    @DemoAnnotation
    public class Demo {
    }
    
    

Java中预置的注解

@Deprecated

该注解用来表示过时的方法、类、成员变量

编译器在编译阶段遇到这个注解会发出警告,告诉我们此时正在调用一个过时

  • 代码模拟

    public class Test {
    
        @Deprecated
        public void speak() {
            System.out.println("out ");
        }
    
        public void say() {
            System.out.println(" now ");
        }
    
    }
    
    public class MyTest {
    
        public static void main(String[] args) {
            Test test = new Test();
              //此时会标注调用的方法过时了
            test.speak();
            test.say();
        }
    }
    
    
@Override

提示字类要复写父类中被@Override修饰的方法

@SuppressWarnings

阻止警告的意思,之前被@Deprecated修饰方法在调用的时候,会发出警告,如果我要忽略掉这种警告可以使用@SuppressWarnings 修饰

@SuppressWarnings("deprecation")
    public static void main(String[] args) {
        Test test = new Test();
        //就不会提示过时
        test.speak();
        test.say();
    }
@SafeVarargs

参数安全类型的注解

目的是提醒开发者不要用参数做一些不安全的操作,它的存在会阻止编译器产生unchecked这样的警告。

在Java1.7版本中加入的。

@FunctionalInterface

函数式接口注解

java1.8版本引入的新特性

函数式接口标记,可以很容易转换成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(); }

注解的提取

形象的比喻就是你把这些注解标签在合适的时候撕下来,然后检阅上面的内容信息。

想要正确检阅注解,离不开一个手段,那就是反射。

注解与反射

注解通过反射获取

上述代码是注解到类上的提取,属性、方法上的注解也是可以提取处理。同样还要借助于反射

  • 代码实操

    @Retention(RetentionPolicy.RUNTIME)
    public @interface TestAnnotation {
    
        int id() default 1;
    
        String msg() default "DashingQi";
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Check {
        String value() default "heihie";
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Perform {
    }
    
    public class MainTest {
        public static void main(String[] args) {
    
            try {
                Field filedA = Test.class.getDeclaredField("a");
                filedA.setAccessible(true);
    
                Check check = filedA.getAnnotation(Check.class);
                if (check != null) {
                    System.out.println("check value = " + check.value());
                }
    
                Method testMethod = Test.class.getDeclaredMethod("testMethod", null);
                if (testMethod != null) {
                    Annotation[] annotations = testMethod.getAnnotations();
                    for (int i = 0; i < annotations.length; i++) {
                        System.out.println(annotations[i].getClass().getSimpleName());
                    }
                }
    
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }
    }
    
    //注意想要在代码运行期间获取到注解,那么@Retention(RetentionPolicy.RUNTIME)是必须的
    
    //运行结果如下
    check value = haha
    $Proxy2
    

注解的用处

  • 提供信息给编译器:编译器可以利用注解来探测错误和警告信息。
  • 编译阶段的处理:软件工具可以利用注解信息来生成代码、Html文档或者做其他相应处理。(@Document)
  • 运行时的处理:某些注解可以在程序运行时接受代码的提取

官方解释:注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。

值得注意的是 注解不是代码本身的一部分

注解是给编译器或者APT(Annotation Processing Tool)用的

注解到底有什么用?取决于你像用它来干什么

Android中注解的应用实例

JUnit测试框架

ButterKnife

Dagger2

Retrofit

注解知识点

注解知识点.png

你可能感兴趣的:(Java基础_注解)