一、Java注解概述
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
二、jdk的内置注解
2.1 内置注解分类
2.1.1 @Override
标记在成员方法上,用于标识当前方法是重写父类(父接口)方法,编译器在对该方法进行编译时会检查是否符合重写规则,如果不符合,编译报错。
这里解释一下@Override注解,在我们的Object基类中我们都知道有一个toString方法,我们通常在实体类中去重写此方法来达到打印对象信息的效果,这时候也会发现重写的toString方法上方就有一个@Override注解。如下所示:
于是,我们试图去改变重写后的toString方法名称,将方法名改为toStrings。你会发现在编译期就报错了!如下所示:
那么这说明什么呢?这就说明该方法不是我们重写其父类(Object)的方法。这就是@Override注解的作用。
2.1.2 @Deprecated
表示建议不再使用该元素。若某类或某方法加上该注解之后,表示此方法或类不再建议使用,在调用时也会出现删除线。但是,也并非代表完全不能使用,只是不推荐,因为还有更好的方法可以调用。
举个例子吧:
假设某手机下拥有某APP,目前是V1.0版本,它为用户提供了show1方法的功能。这时候APP对show1方法的功能又进行了扩展,打算发布V2.0版本。但是,我们V1.0版本需要抛弃吗?答案肯定是不能抛弃的,因为有一部分用户是一直用V1.0版本的。如果抛弃了该版本会损失很多的用户量,所以我们不能抛弃该版本。这时候,我们对功能进行了扩展后,发布了V2.0版本,我们给予用户的通知就可以了,也就是告知用户我们在V2.0版本中为功能进行了扩展。可以让用户自行选择版本。
但是,除了发布告知用户版本情况之外,我们还需要在原来版本的功能上给予提示,在上面的模拟场景中我们需要在show1方法上方加@Deprecated注解给予提示。通过这种方式也告知用户“这是旧版本时候的功能了,我们不建议再继续使用旧版本的功能”,这句话的意思也就正是给用户做了提示。用户也会这么想“奥,这版本的这个功能不好用了,肯定有新版本,又更好用的功能。我要去官网查一下下载新版本”,还会有用户这么想“我明白了,又更新出更好的功能了,但是这个版本的功能我已经够用了,不需要重新下载新版本了”。
public class DeprecatedTest {
@Deprecated
public void show1() {
System.out.println("这是V1.0系统。");
}
public void show2() {
System.out.println("这是V2.0系统,功能更多。");
}
}
那么我们怎么查看我上述所说的在功能上给予的提示呢?这时候我需要去创建一个方法,然后去调用show1方法,并查看调用时它是如何提示的。
其实,在官方API中也是通过该方式来标注已经过时(不再推荐的方法或类等元素),例如:java.util.Date
2.1.3 @SuppressWarnings
压制警告注解,可放置在类和方法上,该注解的作用是阻止编译器发出某些警告信息。
为了解释@SuppressWarnings注解,我们还使用上一个例子,因为在那个例子中就有黄色的warning出现。他说show2()方法和useApp()方法未被使用。
简单来说,你创建的show2()和useApp()方法,但是你在代码中并没有调用过此方法。以后你便会遇到各种各样黄色的warning。然后, 我们就可以使用不同的注解参数来压制不同的注解。但是在该注解的参数中,提供了一个all参数可以压制全部类型的警告。而这个注解是需要加到类的上方,并赋予all参数,即可压制所有警告。如下:
除了该处使用的"all以外@SuppressWarnings还有许多其它参数;常用参数如下:
- unchecked:未检查的转化,如集合没有指定类型还添加元素
- unused:未使用的变量
- resource:有泛型未指定类型
- path:在类路径,原文件路径中有不存在的路径
- deprecation:使用了某些不赞成使用的类和方法
- fallthrough:switch语句执行到底没有break关键字
- rawtypes:没有写泛型,比如: List list = new ArrayList();
- all:全部类型的警告
2.1.4 @SafeVarargs
在JDK 7中引入了@SafeVarargs,该注解主要用于处理可变长参数中的泛型。
2.1.5 @FunctionalInterface
@FunctionalInterface注解用于指定接口是函数式接口。
三、元注解
元注解就是用来描述注解的注解。一般使用元注解来限制自定义注解的使用范围、生命周期等等。常见的元注解有:
- @Target
- @Retention
- @Inherited
- @Documented
3.1 @Target
@Target注解用于确定Annotation所修饰的对象。我们知道Annotation可用于packages、types(类、接口、枚举)、类型成员(方法、成员变量、枚举值)、方法参数等等。所以,可用@Target表示Annotation修饰的目标。
同一个注解可作用于多种元素。例如:某注解既可以在方法上使用也可以在类上面。
在java.lang.annotation包中通过枚举ElementType定义注解修饰的目标,代码如下:
public enum ElementType {
/**标明该注解可以用于类、接口(包括注解类型)或enum声明*/
TYPE,
/** 标明该注解可以用于字段(域)声明,包括enum实例 */
FIELD,
/** 标明该注解可以用于方法声明 */
METHOD,
/** 标明该注解可以用于参数声明 */
PARAMETER,
/** 标明注解可以用于构造函数声明 */
CONSTRUCTOR,
/** 标明注解可以用于局部变量声明 */
LOCAL_VARIABLE,
/** 标明注解可以用于注解声明(应用于另一个注解上)*/
ANNOTATION_TYPE,
/** 标明注解可以用于包声明 */
PACKAGE,
/**
* 标明注解可以用于类型参数声明
* @since 1.8
*/
TYPE_PARAMETER,
/**
* 类型使用声明
* @since 1.8
*/
TYPE_USE
}
在此,我们来看看熟悉的注解@Override的源码:
从此处,我们可以看到:使用@Target注解指定@Override注解只能作用于方法。
接下来,我们再来看看熟悉的注解@Deprecated的源码:
3.2 @Retention
Java文件从生成到执行,要经过三个主要的阶段:java源文件,class文件,JVM运行。
@Retention定义了Annotation的保留策略,它亦类似于开发过程中常提到的生命周期。我们可通过@Retention指定Annotation保留至哪个阶段。有的Annotation仅出现在源代码中而被编译器丢弃,而另一些却可以保留至class文件。类似地,有的在class文件中的Annotation在运行时会被虚拟机忽略,而另一些在运行时被读取。
在此,我们来看看熟悉的注解@Override的源码:
从此处,我们可以看到:使用@Retention注解指定@Override注解仅保留在源码阶段。
接下来,我们再来看看熟悉的注解@Deprecated的源码:
从此处,我们可以看到:使用@Retention注解指定@Deprecated注解将保留至运行阶段。
3.3 @Inherited
@Inherited用于指示注释类型的自动继承。例如,如果某个类使用了被@Inherited修饰的注解,则其子类将自动具有该注解。
第一步:自定义注解
package com.annotation.test2;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedAnnotation {
String value();
}
第二步:在父类中使用自定义注解
package com.annotation.test2;
@InheritedAnnotation("@InheritedAnnotation on class of ParentClass")
public class ParentClass {
}
第三步:子类继承父类
package com.annotation.test2;
/**
* Created with IntelliJ IDEA.
*
* @Author: Is good
* @Description:
*/
public class ChildClass extends parentClass{
}
第四步:从子类上获取注解并测试
package com.annotation.test2;
/**
* Created with IntelliJ IDEA.
*
* @Author: Is good
* @Description:测试元注解@Inherited
*/
public class TestAnnotation {
public static void main(String[] args) {
Class<?> clazz = ChildClass.class;
Class<InheritedAnnotation> annotationClass=InheritedAnnotation.class;
boolean isPresent=clazz.isAnnotationPresent(annotationClass);
if (isPresent) {
InheritedAnnotation annotation = (InheritedAnnotation) clazz.getAnnotation(annotationClass);
String value = annotation.value();
System.out.println("value=" + value);
}
}
}
3.4 @Documented
@Documented表示在生成javadoc文档时将该Annotation也写入到帮助文档。
还拿api中过时的Date中的方法来说,在api中显示Date中的getYear方法是这样的。
正如你看到的,注解在api中显示了出来,证明该注解是@Documented注解修饰并文档化的。那我们就看看这个注解是否被@Documented修饰吧。
4、总结
又是学习的一天,还有很多的东西需要进一步地掌握。如有错误,请指正。