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 <code>Runnable</code> is used
         * to create a thread, starting the thread causes the object's
         * <code>run</code> method to be called in that separately executing
         * thread.
         * <p>
         * The general contract of the method <code>run</code> is that it may
         * take any action whatsoever.
         *
         * @see     java.lang.Thread#run()
         */
        public abstract void run();
    }
    

注解的提取

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

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

注解与反射

注解通过反射获取

  • 通过Class对象的isAnnotationPresent()方法判断它是否应用了某个注解

    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
            return GenericDeclaration.super.isAnnotationPresent(annotationClass);
        }
    
  • 通过getAnnotation()方法或者getAnnotations()来获取Annotation对象

    前者是返回指定类型的注解,后者是返回注解到这个元素上的所有注解

    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
          
        }
    public Annotation[] getAnnotations() {
         
        }
    
  • 如果获取的Annotation对象存在,那么我们可以调用它们的属性方法了。

  • 代码实操

    // 定义一个注解
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface TestAnnotation {
    
        int id() default 1;
    
        String msg() default "DashingQi";
    }
    
    //将定义好的注解应用到元素上
    @TestAnnotation(id = 4, msg = "zhangqi")
    public class Test {
    }
    
    //执行代码
    public class MainTest {
        public static void main(String[] args) {
            Class<Test> testClass = Test.class;
            //判断Test类对应的Class中是否应用了TestAnnotation注解
            boolean annotationPresent = testClass.isAnnotationPresent(TestAnnotation.class);
            if (annotationPresent) {
                //获取到应用的注解
                TestAnnotation annotation = testClass.getAnnotation(TestAnnotation.class);
                //获取到对应的注解之后,获取注解的成员变量
                System.out.println("id = " + annotation.id());
                System.out.println("msg = " + annotation.msg());
            }
        }
    }
    
    //运行结果如下
    id = 4
    msg = zhangqi
    

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

  • 代码实操

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

推荐阅读更多精彩内容

  • 文章开头先引入一处图片。 这处图片引自老罗的博客。为了避免不必要的麻烦,首先声明我个人比较尊敬老罗的。至于为什么放...
    小乖心塞阅读 351评论 1 0
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和...
    九尾喵的薛定谔阅读 3,141评论 0 2
  • 夯实 Java 基础 - 注解 不知道大家有没有一种感觉,当你想要了解某个知识点的时候,就会发现好多技术类 APP...
    醒着的码者阅读 1,044评论 4 7
  • 什么?还不会使用注解Annotation?!基础差的同学赶紧补习吧!😅1.作用2.定义注解3.处理注解4.使用 1...
    CoderShang阅读 217评论 0 2
  • 基本概念 在JAVA中我们都知道有注释的概念,注释有单行注释多行注释文档注释。这种注释是给开发人员看的。而在JAV...
    So_ProbuING阅读 420评论 0 0