java内置注解
作用在代码的注解
@Override
- 重写注解,标注在方法上,无属性。
该注解告诉编译器,该方法是重写方法,编译器则会判断其实现的接口或其父类有无该方法,无则编译报错。
@Deprecated
- 过时注解,标注在类、属性、方法、参数、包、构造器和局部变量上,无属性。
该注解表示该类或者方法为已经废弃的,只是为了兼容以前的程序,调用处也会出现删除线,不建议使用,建议使用新的方法或者类。
Java 9 中注解增加了两个新属性:
since: 该属性指定已注解的API元素已被弃用的版本。
forRemoval: 改属性表示注解的 API 元素在将来的版本中被删除,应该迁移 API。*
@SuppressWarnings
- 抑制编译器警告注解,标注在类、属性、方法、参数、构造器和局部变量上,属性为
String[] value()
。
该注解的作用是告诉编译器取消标注代码的指定的警告。
@SuppressWarnings("unchecked")
抑制单类型的警告
@SuppressWarnings({"unchecked","rawtypes"})
抑制多类型的警告
@SuppressWarnings("all")
抑制所有类型的警告
建议把注解放在最近进警告发生的位置。
@SafeVarargs
- 抑制堆污染警告注解,标注在构造器和方法上,无属性。
该注解的作用是告诉编译器取消unchecked警告。
unchecked警告是什么?
Heap Pollution堆污染,首先我们看下什么是堆污染:
某个 可变泛型参数 指向的对象 并不是该泛型参数,而是无泛型参数。
举个栗子:
//此时test方法的入参是List<String>
public static void test(List<String> list) {
}
public static void main(String[] args) {
List list = Lists.newArrayList();
list.add(1);
//test方法的入参(可变泛型参数)指向的并不是List<String>,而是List(无泛型参数)
test(list);
}
这种情况就会发生堆污染,此时编译器会提示我们unchecked警告。
而堆污染还可能导致ClassCastException
异常,比如在test
方法体中添加对List<Integer>
的操作。
public static void main(String[] args) {
List list = Lists.newArrayList();
list.add(1);
test(list);
}
public static void test(List<String> list) {
String a = list.get(0);
}
运行代码抛出ClassCastException
异常
所以在使用@SafeVarargs
注解时,保证在不会出现ClassCastException
异常时,加到方法上以消除警告。
使用的时候要注意:@SafeVarargs注解,对于非static或非final声明的方法,不适用,会编译不通过。
@FunctionalInterface
- 函数式接口注解,标注在接口上,无属性
该注解只能标志在"有且仅有一个抽象方法"的接口上。
有且仅有一个抽象方法不包括JDK8接口中的静态方法和默认方法,不包括覆盖了Object中方法。
该注解不是必须的,如果一个符合函数式接口要求的接口加不加该注解都可以,但是如果不满足要求加该注解则会编译报错。
举个栗子:
@FunctionalInterface
public interface TestInterface {
//唯一的抽象方法
public void test();
public int hashCode();
public static void test1(){
}
}
作用在注解的注解(元注解)
@Target
- 指定注解的使用范围
ElementType.TYPE
:类、接口、注解、枚举ElementType.FIELD
:字段、枚举常量ElementType.METHOD
:方法ElementType.PARAMETER
:形式参数ElementType.CONSTRUCTOR
:构造方法ElementType.LOCAL_VARIABLE
:局部变量ElementType.ANNOTATION_TYPE
:注解ElementType.PACKAGE
:包ElementType.TYPE_PARAMETER
:类型参数
举个栗子:
@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.CLASS)
public @interface TestAnnotation {
}
class Test<@TestAnnotation T> {
public <@TestAnnotation U> U foo(U u) {
return null;
}
}
ElementType.TYPE_USE
:类型使用
可以指定任何类型,举个栗子:
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.CLASS)
public @interface TestAnnotation {
String value() default "a";
}
@TestAnnotation
@interface TestAnnotation1 {
}
@TestAnnotation
class Test<@TestAnnotation T> {
@TestAnnotation Test() {
}
@TestAnnotation
private Integer n;
@TestAnnotation
public <@TestAnnotation U> U foo(U u) {
return null;
}
@TestAnnotation
public String fun(@TestAnnotation Integer a) {
@TestAnnotation
Integer b = a;
Object o = (@TestAnnotation Object) a;
@TestAnnotation String text = (@TestAnnotation String) new Object();
n = b;
return "1";
}
}
注意:当使用 ElementType.TYPE_USE
时,方法的返回值若为void,则不可以被使用。
@Retention
- 用于指定注解的保留策略
RetentionPolicy.SOURCE
:注解只保留在源码中,在编译时会被编译器丢弃
栗子:@Override
RetentionPolicy.CLASS
:(默认的保留策略) 注解会被保留在Class文件中,但不会被加载到虚拟机中,运行时无法获得RetentionPolicy.RUNTIME
:注解会被保留在Class文件中,且会被加载到虚拟机中,可以在运行时获得
栗子:@Deprecated
@Documented
- 用于将注解包含在javadoc中
javadoc是Sun公司提供的一个技术,它从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档。也就是说,只要在编写程序时以一套特定的标签作注释,在程序编写完成后,通过Javadoc就可以同时形成程序的开发文档了。
默认情况下,javadoc是不包括注解的,但如果使用了@Documented
注解,则相关注解类型信息会被包含在生成的文档中
@Inherited
- 用于指明父类注解会被子类继承得到
举个栗子:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface TestAnnotation {
String value();
}
@TestAnnotation("test")
class Parent{
}
class Son extends Parent{
public static void main(String[] args) {
TestAnnotation annotation = Son.class.getAnnotation(TestAnnotation.class);
System.out.println(annotation.value());
}
}
@Repeatable
- 用于声明标记的注解为可重复类型注解,可以在同一个地方多次使用
举个栗子:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(BaseAnnotation.class)
public @interface TestAnnotation {
String value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface BaseAnnotation {
TestAnnotation[] value();
}
@TestAnnotation("test")
@TestAnnotation("test1")
@TestAnnotation("test2")
class Son {
public static void main(String[] args) {
BaseAnnotation annotations = Son.class.getAnnotation(BaseAnnotation.class);
for (TestAnnotation annotation : annotations.value()) {
System.out.println(annotation.value());
}
}
}