看完这篇Java注解,我要在学妹面前吹牛皮~


分享一篇 【Java注解+Java反射+Java类加载机制+javaweb 技术搭建MVC框架并用于项目】,更加深入的学习和配置使用所学知识点。


Java注解

Annotation,注解,对于Java基础不扎实的我,只会用而不知道其中的原理,今天让我好好了解一下你。

注解就如我们日常生活中看到的标签,去超时看见商品标签,去服装店看到服装标签。它用来标注类或属性。

1.注解的定义

注解通过 @interface 关键字进行定义,下面创建一个TestAnnotation注解类:

public @interface TestAnnotation {
}

@interface就相当于接口,不过前面多了一个@符号。而此注解,就可以用到类上了。

2.元注解

元注解是一种基本注解,用于定义注解,常在自定义注解的时候使用。它可定义注解的各种属性,元注解有5种:@Retention、@Documented、@Target、@Inherited和@Repeatable

2.1 @Retention(保留)

Retention意为 保留,解释这个注解的保留的时间(存活的时间)。它的取值由RetentionPolicy类提供

Java代码保留(存活)的时间段分为source -> class -> runtime三个。

  • RetentionPolicy.SOURCE:注解只在源码阶段保留,将被编译器丢弃。
  • RetentionPolicy.CLASS:默认行为,注解只被保留到编译进行的时候,不会被加载到 JVM 中。
  • RetentionPolicy.RUNTIME:注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,程序运行时可读取,可被反射读取到。

2.2 @Documented(文档)

Documented意为 文档,解释此注解中的元素在 Javadoc 中去。【点击我查看javadoc解释

2.3 @Target(目标)

Target意为 目标,指定定义的注解起作用的场景。限定注解的使用场景、使用对象等,注解的使用变得十分明确。它的取值由ElementType类提供

  • ElementType.TYPE :作用于类、接口(包括注解类型接口)或者枚举类型。
  • ElementType.FIELD:作用于字段属性。
  • ElementType.METHOD:作用于方法。
  • ElementType.PARAMETER:作用于参数。
  • ElementType.CONSTRUCTOR:作用于构造器。
  • ElementType.LOCAL_VARIABLE:作用于局部变量。
  • ElementType.ANNOTATION_TYPE:作用于注解。
  • ElementType.PACKAGE:作用于包。
  • ElementType.TYPE_PARAMETER:作用于类型参数(since jdk1.8)。
  • ElementType.TYPE_USE:作用于使用的类型(since jdk1.8)。
  • ElementType.MODULE:作用于模块声明(since jdk9)。

2.4 @Inherited(继承)

Inherited意为 继承,它不是指此注解本身会被继承,而是被@Inherited修饰的类的子类,在没有被任何注解修饰的话,那么这个子类就继承了父类的注解。例:

// 1.先定义一个注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}

// 2.B继承A,那么B没有被任何注解修饰,那么B继承A的注解
@Test
public class A {}
public class B extends A {}

2.5 @Repeatable(可重复)

Repeatable意为 可重复,jdk1.8新特性。它表示修饰的注解可以重复被使用。例如:

一个开发人员会使用c、c#和java

// 1.定义容器注解,存储各种各样的Language类型
@Retention(RetentionPolicy.RUNTIME)
@interface Languages{
    Language[] value();
}

// 2.定义Language注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Languages.class)
public @interface Language {
    String tool() default "";

    String value() default "";
}

// 3.使用自定义的注解修饰类
@Language(tool ="c")
@Language(tool ="c#")
@Language(tool ="java")
public class Developer{
    // ...
}

上面的代码中,@Repeatable 注解了 Language。而 @Repeatable 后面括号中的类相当于一个 容器注解。容器注解 是用来存放其它注解的地方,它本身也是一个注解。

代码中的相关容器注解:

@interface Languages{
    Language[] value();
}

按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是 数组


3.注解的属性

注解的属性又称成员变量。

3.1 使用

一般使用

定义的成员变量,应该在使用注解的是赋值,以键值对形式赋值(这里还是以为上面的代码为例):

// 使用@Language
@Language(tool ="c",value = "master")
public class Developer{
    // ...
}

多个属性需要赋值,使用逗号隔开。

单个参数传递

只需要传递一个参数的时候,如果需要传递数据的属性名为value,在对其进行赋值的时候,可以不写value=,直接写一个值即可,如下:

@Language(value = "master")
// 等价于
@Language("master")
无参数传递

当使用的注解,不需要传递参数的时候,就可以不写括号,如下:

@Language()
// 等价于
@Language

3.2 定义

注解当中只有成员变量,没有方法(虽然是方法的声明格式)。注解的成员变量在注解的定义中以普遍Java代码中方法的声明形式来声明,方法明定义了该成员变量的名字,返回值类型定义了该成员变量的类型。

在注解中定义属性时,它的类型必须是 8种基本类型 或 类、接口、注解及它们的数组

8种基本类型:boolean、byte、short、char、int、long、float、double

且属性可以有默认值,使用defalut设置,若属性没有设置默认值,在使用该注解的时候,就必须传递参数。示例:

// 1.有属性的自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Languages.class)
public @interface Language {
    String tool() default "";

    String value() default "";
}

// 2.无属性的自定义注解
public @interface Environment {
}

注解也可以不做任何属性声明,这个时候使用该注解的是,就不用些括号。

至此,就可以自定义注解了。


4.注解的获取(反射)

使用注解修饰类或方法,就是为了指定的场景下能够达到指定的目的,但是注解毕竟只是一个标签,真正实现功能的还得借助Java的反射获取注解信息来实现。

先查看获取注解对象的方法(Class、Method、Field都有):

  1. public <A extends Annotation> A getAnnotation(Class<A> annotationClass):获取指定类型的注解对象。
  2. public Annotation[] getAnnotations():获取全部注解,返回注解数组。

需要使用反射获取到的注解,一定的声明@Retention(RetentionPolicy.RUNTIME),只有保留到RUNTIME才能获取到,否则是会抹去此注解的。

4.1 获取类上注解对象

这里就以获取class类上的注解为例(还是使用上面声明的注解),Developer声明如下:

@Language(tool = "java",value = "master")
public class Developer {
}

下面就是获取并打印

Class c = Developer.class;

// 1.使用getAnnotation() 获取指定的注解
Language language = (Language) c.getAnnotation(Language.class);
System.out.println("tool:"+language.tool());
System.out.println("value:"+language.value());

// 2.使用getAnnotations() 获取全部注解
Annotation[] as = c.getAnnotations();
for(Annotation annotation:as){
    if(annotation instanceof Language){
        System.out.println("tool:"+language.tool());
        System.out.println("value:"+language.value());
    }
}

输出的结果都是:

tool:java
value:master

4.2 类、方法上注解对象

在了解了如何获取类上的注解对象之后,获取属性、方法上的注解对象就简单了,只要获取到Class、Method、Field对象之后,就 调用getAnnotation()getAnnotations() 方法即可获取到对应的注解对象


5.注解的使用需求

学习注解之后,如果没有实际应用,忘记肯定比学的快。如果我们明确了它的使用需求,再加以使用,那当然最好不过。

官方文档对注解的描述:

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

注解有许多用处,主要如下:

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

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

简单点说就是:注解无法改变代码本身,注解只是工具。同时,开发者开发的用于处理 Annotation 的代码统称为APT(Annotation Processing Tool)

说了这么多的概念,不好理解,也记不住,解决方法来了:【点击跳转阅读注解+反射的实际应用】。

同时,spring框架中使用大量的注解,感兴趣可以去看一下源码。


6.Java预设的注解

做一个扩展,点到为止

相信在我们日常写代码的是,有几个注解是接触很多的。

  • @Deprecated:Deprecated意为 弃用、过时,Java语言在不断的迭代中,针对同一需求不断的优化解决方案,旧的解决方案就会使用@Deprecated标记过时,但是还是可以正常使用
  • @Override:重写父类方法需要使用@Override。
  • @SuppressWarnings:阻止警告。
  • @SafeVarargs:参数安全类型注解。
  • @FunctionalInterface:函数式接口注解,这个是 Java 1.8 版本引入的新特性

函数式接口:就是接口中只有一个抽象方法,其他方法都不能是抽象的。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值