Java基础—注解

注解-Annotation


问题:

  • 什么是注解;
  • 为什么要引入注解
  • 注解是如何工作的
  • 如何编写自定义的注解(通过例子)
  • 什么情况下可以使用注解
  • 最新注解和ADF(应用开发框架)。

一.概述

从 JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是 Annotation(注解)

一句话:注解就是一种描述数据的数据。

1)元数据 MetaData:即一种描述数据的数据

2)注解 Annotation:代码里的特殊标记, 这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。 通过使用 Annotation, 程序员可以在不改变原有逻辑的情况下, 在源文件中嵌入一些补充信息

3)Annotation 可以像修饰符一样被使用, 可用于修饰包,类, 构造器, 方法, 成员变量, 参数, 局部变量的声明, 这些信息被保存在 Annotation 的 “name=value” 对中

4)一些应用场景:

在JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在JavaEE/Android中注解占据了更重要的角色,例如用来配置应用程序的任何切面,代替java EE旧版中所遗留的繁冗代码和XML配置等

举例:

@Override
public String toString() {
	return "Override";
}

上面重写了toString()方法,并使用了@Override注解。但是,即使我不使用@Override注解标记代码,程序也能够正常执行。

那么,该注解表示什么?这么写有什么好处吗?

  • @Override告诉编译器这个方法是一个重写方法(描述方法的元数据),如果父类中不存在该方法,编译器便会报错,提示该方法没有重写父类中的方法。
  • 如果不小心拼写错误,例如将toString()写成了toStrring(),而且没有使用@Override注解,那程序依然能编译运行。但运行结果会与期望大不相同。
  • 现在我们了解了什么是注解,并且使用注解有助于阅读程序。

二.为什么要引入注解?

使用Annotation之前(甚至在使用之后),XML被广泛的应用于描述元数据。

  • 注解:是一种分散式的元数据,与源代码紧绑定。
  • xml:是一种集中式的元数据,与源代码无绑定

两者各有利弊:

  • 假如你想为应用设置很多的常量或参数,这种情况下,XML是一个很好的选择,因为它不会同特定的代码相连。
  • 如果你想把某个方法声明为服务,那么使用Annotation会更好一些,因为这种情况下需要注解和方法紧密耦合起来,开发人员也必须认识到这点。
  • 此外,Annotation定义了一种标准的描述元数据的方式。

注解的主要用途:

  1. 生成文档,通过代码里标识的元数据生成javadoc文档。
  2. 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
  3. 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
  4. 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例

目前,许多框架将XML和Annotation两种方式结合使用,平衡两者之间的利弊。

三.注解的定义

注解的使用:使用 Annotation 时要在其前面增加 @ 符号, 并把该 Annotation 当成一个修饰符使用。用于修饰它支持的程序元素。

  1. JDK内置的基本注解类型(3个)
  2. 自定义注解类型[注解的简单定义]
  3. 元注解:对注解进行注解(4个)
    @Documented –注解是否将包含在JavaDoc中
    @Retention –什么时候使用该注解
    @Target –注解用于什么地方
    @Inherited – 是否允许子类继承该注解
  4. 利用反射获取注解信息

1.JDK的注解类型

1.JDK内置的基本注解

  • @Override: 编译时检查当前这个方法是否满足重写的条件, 该注解只能用于方法

  • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时

  • @SuppressWarnings: 抑制编译器警告

    • 可以修饰:类, 构造器, 方法, 成员变量, 参数, 局部变量

2.单元测试中应用的注解

作用:用于替代配置文件

  • @Test 应用在方法上:public修饰的类中public修饰的方法
  • @Before 修饰的方法:会在每个测试方法执行之前执行
  • @After 修饰的方法:会在每个测试方法执行之后执行
  • @BeforeClass 要求被修饰的方法是静态的,在所有Test方法[测试方法]之前执行一次
  • @AfterClass 要求被修饰的方法是静态的,在所有Test方法[测试方法]之后执行一次

案例:

public class Demo2 {
	@BeforeClass
	public static void beforeClass(){
		System.out.println("beforeClass....");
	}

	@AfterClass
	public static void afterClass(){
		System.out.println("afterClass...");
	}

	@Before
	public void before(){
		System.out.println("before all test.....");
	}

	@After
	public void after(){
		System.out.println("after all test...");
	}
	
	@Test
	public void test1(){
		System.out.println("测试方法1");
	}

	@Test
	public void test2(){
		System.out.println("测试方法2");
	}
	//如果执行全部测试单元的话输出结果为
	//	beforeClass....
	//	before all test.....
	//	测试方法1
	//	after all test...
	//	before all test.....
	//	测试方法2
	//	after all test...
	//	afterClass...
}

2.元注解

元注解:对注解的解释或设置——加在注解的定义上(注解的注解)

2.1 元注解的类型

4个元注解都是在jdk的java.lang.annotation包下面

1)@Retention: 保留策略——设置该注解在什么时刻有效;使用 RetentionPolicy 枚举类型的参数

public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

2)@Target:目标——决定可以用来修饰什么数据;使用 ElementType 枚举类型的参数

public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

3)@Documented:能否在生成的帮助文档中显示 文档注释

public @interface Documented {}

4)@Inherited:继承

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类

注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

3.注解的自定义

1.语法:

[@元注解]
[修饰符] @interface 注解名{}

2.自定义注解的参数设置

public @interface MyAnnotation{
	String name() default “annotation";
}

1)注解成员的定义格式:

  • 数据类型 名称() [default 值];

    String value() default “java”;
    String[] value() default “java”; -->数组参数

2)使用时的传参格式:

  • @元注解(名称=值 [,参数2] )
  • @元注解(名称={值1,值2} )

3)当参数名称是 value() ,并且只有一个参数时:

  • 传参时 value= 是可以省略的;
  • 否则不可省略名称;
@interfaceAuthor{
   String value();
}
//注解的使用
@Author("Yashwant")
public void someMethod() {
}

4)当参数是数组类型时:

  • 参数只有一个值时,使用 名称 = 值 即可;
  • 参数有多个值时,使用 名称 = {值……}

3)参数的类型可以是:

  • 八大基本数据类型
  • String
  • 枚举
  • 以上的数组类型

3.案例

// 定义一个可以注解在METHOD上的注解
@Target({ElementType.METHOD})
//保留策略:运行时
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethod {
    // 定义注解的一个元素 并给定默认值
    String value() default "我是定义在方法上注解的元素value的默认值";
}

四.注解的使用

前面描述了注解是如何定义的,但注解是如何使用,更重要的的是其是如何发挥作用的呢?

1.注解的作用机制

通过反射,获取对应元素上的注解,根据注解内容以及元素内容进行判断。

@Test
public void testAnnotation() {
	//1.获取对应类的Class对象
	Class calzz = Class.forName("全类名");
	//2.获取Class对象的注解们
	Annotation[] annotations = clazz.getAnnotations();
	//3.遍历打印注解的简单名称
	for (Annotation annotation : annotations) {
		//1)获取该注解的Class对象
		Class<? extends Annotation> annotationType = annotation.annotationType();
		//2)打印注解Class对象的简单名称
		System.out.println(annotationType.getSimpleName());
	}
}

2.Annotation类(java.lang.reflect.Annotation):

Annotation类型定义了Annotation的名字、类型、成员默认值。

一个Annotation类型可以说是一个特殊的java接口,它的成员变量是受限制的,而声明Annotation类型时需要使用新语法。当我们通过java反射API访问Annotation时,返回值将是一个实现了该 annotation类型接口的对象,通过访问这个对象我们能方便的访问到其Annotation成员。

3.注解处理器类库(java.lang.reflect.AnnotatedElement)

Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。

除此之外,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素,该接口主要有如下几个实现类(如下图所示):

  • Class:类定义
  • Constructor:构造器定义
  • Field:累的成员变量定义
  • Method:类的方法定义
  • Package:类的包定义

java.lang.reflect 包所有提供的反射API,扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

而AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的Class对象、Method对象……之后,程序就可以调用该对象实现的AnnotatedElement接口的四个方法,来访问Annotation信息:

  • T getAnnotation(Class annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
  • Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
  • boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
  • Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注释。(如果没有注释直接存在于此元素上,则返回长度为零的一个数组)

4.注解的使用案例:

https://blog.csdn.net/zhang0558/article/details/52643016

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值