一、概念
Annotation(注解)就是Java提供了一种源程序中的元素关联任何信息和任何元数据(metadata)的途径和方法。
定义:注解(Annotation),也叫元数据,是一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释,创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查等。从某些方面看,Annotation就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在Annotation的“name=value”结构对中。
Annotation(注解)是一个接口,程序可以通过反射来获取指定程序元素的Annotation对象,然后通过Annotation对象来获取注解里面的元数据。
1、Annotation和Annotation类型
Annotation:
Annotation使用了在java5.0所带来的新语法,它的行为十分类似public、final这样的修饰符。每个Annotation具有一个名字和成员个数>=0。每个Annotation的成员具有被称为name=value对的名字和值(就像javabean一样),name=value装载了Annotation的信息。
Annotation类型:
Annotation类型定义了Annotation的名字、类型、成员默认值。一个Annotation类型可以说是一个特殊的java接口,它的成员变量是受限制的,而声明Annotation类型时需要使用新语法。当我们通过java反射API访问Annotation时,返回值将是一个实现了该 Annotation类型接口的对象,通过访问这个对象我们能方便的访问到其Annotation成员。
Annotation的成员在Annotation类型中以无参数的方法的形式被声明。其方法名和返回值定义了该成员的名字和类型。在此有一个特定的默认语法:允许声明任何Annotation成员的默认值:一个Annotation可以将name=value对作为没有定义默认值的Annotation成员的值,当然也可以使用name=value对来覆盖其它成员默认值。这一点有些近似类的继承特性,父类的构造函数可以作为子类的默认构造函数,但是也可以被子类覆盖。
2、什么是metadata(元数据)
元数据从metadata一词译来,就是“关于数据的数据”的意思。
元数据的功能作用有很多,比如:你可能用过javadoc的注释自动生成文档。这就是元数据功能的一种。总的来说,元数据可以用来创建文档,跟踪代码的依赖性,执行编译时格式检查,代替已有的配置文件。如果要对于元数据的作用进行分类,目前还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:
1)、编写文档:通过代码里标识的元数据生成文档;
2)、代码分析:通过代码里标识的元数据对代码进行分析;
3)、编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。
在Java中元数据以标签的形式存在于Java代码中,元数据标签的存在并不影响程序代码的编译和执行,它只是被用来生成其它的文件或正在运行时知道被运行代码的描述信息。
综上所述:
第一,元数据以标签的形式存在于Java代码中。
第二,元数据描述的信息是类型安全的,即元数据内部的字段都是有明确类型的。
第三,元数据需要编译器之外的工具额外的处理用来生成其它的程序部件。
第四,元数据可以只存在于Java源代码级别,也可以存在于编译之后的Class文件内部。
二、Java中常见的注解
1、注解的分类
1)、按照运行机制分
源码注解:注解只在源码中存在,编译成class文件之后就不存在了;
编译时注解:注解在源码和class文件中都存在(@Override、@Deprecated、@Suppvisewarnings);
运行时注解:在运行阶段还在起作用,甚至会影响程序的运行逻辑。
2)、按照来源划分
来自JDK的注解
来自第三方的注解(使用最多)
自定义注解
3)、另外还有一种较特殊的注解
元注解:注解的注解。
2、JDK自带注解
注解的语法比较简单,除了@符号的使用外,他基本与Java固有的语法一致,JavaSE中内置三个标准注解,定义在java.lang中:
@Override:用于修饰此方法覆盖了父类的方法;
@Deprecated:用于修饰已经过时的方法;
@SuppressWarnnings:用于通知java编译器禁止特定的编译警告。
2.1、@Override
@Override,限定重写父类方法:@Override 是一个标记注解类型,它被用作标注方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。 如果我们使用了这种Annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。这个Annotation常常在我们试图覆盖父类方法而确又写错了方法名时发挥威力(因此建议在重载父类方法时加上该注解)。使用方法极其简单:在使用此Annotation时只要在被修饰的方法前面加上@Override即可。下面的代码是一个使用@Override修饰一个企图重载父类的displayName()方法,而又存在拼写错误的实例:
/**
* @Description: @Override注解的使用
* @author: zxt
* @time: 2019年1月24日 下午6:53:12
*/
public class Fruit {
public void displayName() {
System.out.println("水果的名称是:***!");
}
}
class Orange extends Fruit {
@Override
public void displayName() {
System.out.println("水果的名称是:桔子!");
}
}
/**
* @Description: 当没有重载父类方法(或者写错方法名)时使用了@Override将报编译时错误
*
*/
class Apple extends Fruit {
// @Override
public void displayname() {
System.out.println("水果的名称是:苹果!");
}
@Override
public void displayName() {
System.out.println("水果的名称是:苹果!");
}
}
2.2、@Deprecated
标记已过的方法,同样@Deprecated也是一个标记注解。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。 而且这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要报警。
值得注意的是,@Deprecated这个Annotation类型和javadoc中的 @deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过时、它应当如何被禁止或者替代的描述)。
在java5.0,java编译器仍然像其从前版本那样寻找@deprecated这个javadoc的tag,并使用它们产生警告信息。但是这种状况将在后续版本中改变,我们应在现在就开始使用@Deprecated来修饰过时的方法而不是 @deprecated这个javadoc tag。
/**
* @Description: @Deprecated注解的使用
* @author: zxt
* @time: 2019年1月24日 下午7:54:40
*/
class AppleService {
public void displayName() {
System.out.println("水果的名称是:苹果!");
}
/**
* @Description:@Deprecated标记方法已经过时,不推荐使用
*/
@Deprecated
public void showTaste() {
System.out.println("水果的苹果的口感是:脆甜");
}
public void showTaste(int typeId) {
if (typeId == 1) {
System.out.println("水果的苹果的口感是:酸涩");
} else if (typeId == 2) {
System.out.println("水果的苹果的口感是:脆甜");
} else {
System.out.println("水果的苹果的口感是:超甜");
}
}
}
public class FruitRun {
public static void main(String[] args) {
Apple apple = new Apple();
apple.displayName();
AppleService appleService = new AppleService();
appleService.showTaste();
appleService.sh