(十八)注解

回忆一下,在Java文件中,除了我们的代码,还能“合法”的存在别的东西吗?——注释

注释是Java语言提供给我们的,在代码中增加“额外”信息的一种方式,这些额外信息,有时不太合适,或不能用Java代码来表示。
注释中的描述,是一种人为的约定
javac在编译时,对其“视而不见”
只有固定语法,没有标准形式

因此,注释中表达的描述代码或者代码之外的信息,只有人能看懂。

一、注解的引入

注解:为我们在代码中添加信息,提供了一种形式化(标准化,甚至连额外信息的表示都是通过java相应的数据类型的值来表示)的方法,使我们可以在稍后的某个时刻非常方便的使用这些信息(通过代码来获取,并使用这些定义的额外信息)。

其实我们之前已经不自觉的使用过注解了:
@Override:检查子类确实是覆盖了父类的方法
// 在使用时,就是在向编译器传达一种额外信息,该方法要覆盖父类中的方法。
@Deprecated:说明已经过时了。
过时:官方已经不推荐使用该方法(这些方法可能有一定的潜在缺陷),在后续的jdk中,可能会删除该方法。

注意事项:
注解本身,只是用来传达一种代码之外的额外的说明信息,但是,通常注解都会有一些特殊的效果表现来,但这些特殊效果和注解本身没有关系,注解只用来传达信息,而是由注解的接收者来产生,比如报错的效果是由编译器来产生。
注解只和信息相关,至于获取到这个信息“人”他们在获取到该信息之后,会产生的效果,和注解本本身无关。

二、 注解的定义(标准形式)

Java语言中本身只定义了极少数的注解,不能满足我们所有的需求,但是Java语言,可以让我们自定义注解,满足自己的需求。

自定义注解格式

public @interface 注解名 { 
  	定义体
}

注意事项:
1.注解的定义和类定义,接口定义非常像(尤其是接口)。
2.注解与类、接口在java语言中的地位一样, 它也代表数据类型,定义的一个注解就是一种数据类型。
一个注解数据类型,定义了:
a.具体包含少条具体的信息;
b.每种信息是怎样的;
注意,注解体中定义的每一条具体的信息都有标准形式。
3.@必不可少,少了@就成了接口定义了。
4.注解之间不能继承。

注解体的定义格式:

@interface 注解名 {

    // 第一条信息的标准形式
   返回值类型  方法名1();   // 这就是某种类型额外信息中的,一条信息的标准化的格式定义
                         // 方法名代表一条信息的名字
                         // 该条信息数据取值类型
   // 第二 条信息的标准形式
   返回值类定  方法名2();
   ...
 }

举个例子:
定义一个注解类型,表示学生年龄取值范围的约束:
1.包含两条信息
2.一个注解类型, 包含的每一条信息,都有自己的名字 -> 方法名
3. 一个注解类型,包含的每一条信息的数据类型 -> 方法的返回值

 @interface  AgeConstraint {

       // 第一条(学生年龄取值的上界)
        int  upperBound();

      // 第二条(学生年龄取值的下界)
        int lowerBound();
    }

自定义注解体的说明:

  1. 注解体的格式类似于接口中的方法定义,但含义完全不同
  2. 方法名就是数据的名称,方法的返回值类型,表示数据值的类型。
  3. 每一条注解信息,它的取值的类型只能是以下几种:
    a. 所有的基本数据类型
    b. String类型
    c. Class类型
    d. 注解类型
    e. 以及以上类型的数组
    不能是类或者接口类型

三、注解的使用(赋值)

定义某种类型的注解,实际上也就是定义了某种类型的额外信息(注解)的“标准形式”。
定义好了注解的标准形式,那么我们就要来使用注解了:
使用注解就是使用某个注解类型的注解实例给java代码添加额外信息。

类比:
注解类型 类比于 类
注解实例 类比于 对象

注解使用的语法:
@注解的类型名(属性名1=属性值1,属性名2=属性值2,…) // 注解实例(注解对象)
这里的属性名:是注解中定义的一条信息的名称。

注解使用的实质,是创建某个类型的注解实例,并且给该实例中的每个属性赋值,从而,一个注解实例表示了一条具体的额外信息。

注意事项:
在使用注解实例的时候,一定要保证,注解定义中的每条数据(每一个属性),必须有确定值(每个属性必须有值):

  1. 在使用注解实例的时候,给每一个属性显示赋值。
  2. 可以在定义注解的时候,给注解中定义的某个属性,声明默认值。默认值的含义是指,当在使用注解实例的时候,如果没有给某属性显示赋值,此时如果该属性定义了默认值,那么在注解实例中该属性的值就会自动取默认值。
  3. 对于合法的引用类型的数据, 比如String类型, 它的默认取值不能是null。
  4. 在有一种特殊情况下,对于注解实例中的属性赋值可以稍作简化,条件是:
    a. 属性名称固定 value
    b. 当在注解实例中,仅仅只需要给value属性赋值的时候
    当且仅当, 在注解实例中,给满足上述两个条件的属性赋值时,可以简化赋值,在赋值时可省略value=。

四、注解的处理

注解的处理(定义注解处理器,用来接收并处理通过注解添加到java代码中的额外信息)

五、元注解

在定义自定义注解的时候,我们可以使用元注解,来声明自定义注解的一些特殊属性
元注解: 注解的注解(描述注解的注解)

Java中提供了4种元注解,我们最常用的是其中2个

@Target 该注解,用来声明和限定注解使用的地方(目标)

  1. 整个类或接口 ElementType.TYPE
  2. 成员变量 ElementType.FIELD
  3. 构造方法 ElementType.CONSTRUCTOR
  4. ElementType.METHOD

虽然一种类型的注解实例,可以作用域多种目标(类,成员变量,构造方法,成员方法)
但是,不管注解实例是添加在哪里的,我们都有办法去获取它。
isAnnotationPresent(Class type) 判断指定目标上是否添加了注解
getAnnotation(Class type) 在指定目标上获取指定类型的注解实例

  1. 作用在类上 Class对象.
  2. 成员变量 Field对象.
  3. 方法 Method对象.
  4. 构造方法 Constructor对象.

@Rentention 该注解用来声明注解的保留级别
1.RetentionPolicy.RUNTIME JVM在运行时,也会保留注解信息
2.RetentionPolicy.CLASS 注解在class文件中可用,但会被JVM丢弃(内存没有)
3.RetentionPolicy.SOURCE 注解将被编译器丢弃(class文件中没有)
注解默认情况下的保留级别是CLASS(运行时已经没了)

@Target 该注解用来声明和限定注解使用的地方
注解可以定义在如下位置

  • 定义在类上 ElementType.TYPE
  • 定义成员变量上 ElementType.FIELD
  • 定义在构造方法上 ElementType.CONSTRUCTOR
  • 定义在成员方法上ElementType.METHOD
    可以同时声明,注解使用在多个位置
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值