认识注解(一)
想要了解注解,就要知道注解是什么,有什么作用,怎么声明和使用注解,最后要知道java api中常用的预定义的注解。
一、注解是什么
注解是为代码提供一些信息,但是注解又不是这段代码的一部分。
这个概念容易让人想到代理模式,但是两者之间的区别又很明显。静态代理需要为每个类生成一个代理类,很不方便;动态代理是通过反射实现的,只能在运行时起作用。
而注解既可以在编译时提供警告,如unchecked警告,也可以在运行时实现一些功能。
这个就有点像做菜的作料一样,你不加也可以吃,加了可以做出更美味的菜肴。可以在做之前加,也可以在做的时候加。
二、注解有什么作用
1.可以用于编译时的检测错误和抑制警告。如@Override注解可以检测重写方法时的错误和@SuppressWarning抑制泛型和使用遗弃的代码所产生的警告。
2.生成文档,如注释文档和xml文件。如@Documented注解。
3.用于运行时。但是运行时注解是在运行时使用反射实现功能,所以大量使用运行时注解时,会影响程序的性能。
三、如何声明一个注解
声明一个注解和声明一个接口非常相似,下面定义了一个简单的注解Test,只有一个元素name。看到声明一个注解和区别是在interface关键字前面加一个@符号。第二个区别是可以在元素后面加默认值。
@Target(ElementType.METHOD)
public @interface Test{ String name() default ""; }
注解元素的类型只能用限定的几种类型——所有基本类型、String、Class、enum、Annotation和以上类型的数组。如果使用其它类型,编译器就会报错。
四、如何使用注解
1.在使用注解前一定要了解@Target元注解,因为它的取值规定了注解可以在什么地方使用。如上面的@Test注解中@Target注解的取值为ElementType.METHOD,就只能在方法上使用。
如果想要在类上使用该注解,就需要取值为ElementType.TYPE。
2.使用注解时,所有的元素都要取值,要么在使用的时候给元素赋值,要么在声明的时候定义默认值。
3.当元素的名称为value时,可以省略名称。当所有元素都取默认值时,可以省略括号。
4.一个注解的元素可以取多个值,取多个值时用大括号包含起来,如@SuppressWarnings({"unchecked", "deprecation"})。但是不能将一个注解多次使用在一个地方,如果想多次使用,则需要声明该注解为@Repeatable。
@Target(ElementType.METHOD) public @interface Test1{ String name() default ""; int value() default 0; } public class Demo{ @Test1(value=1, name="小明") public void f() {} @Test1(2) public void h(){}
@Test1
public void k() {}
}
五、java api中预定义的一些注解
1.元注解:专门用于注解其他注解的注解
(1)@Target:声明注解用于什么地方。取值为枚举类型ElementType中的值。
1)ElementType.TYPE:注解可以注解在类、接口(包括注解类型)和enum的声明上。
2)ElementType.ANNOTATION_TYPE:注解可以用于注解的声明上。
3)ElementType.CONSTRUCTOR:注解可以用于构造器声明上。
4)ElementType.METHOD:注解可以用于方法声明上。
5)ElementType.PARAMETER:注解可以用于参数声明上。
6)ElementType.LOCAL_VARIABLE:注解可以用于局部变量的声明上。
7)ElementType.FIELD:注解可以用于域的声明上。
8)ElementType.PACKAGE:注解可以用于包的声明上。
(2)@Retention:声明需要在什么级别上保存注解信息。取值为枚举类型RetentionPolicy中的常量值。
1)Retention.SOURCE:源码级别,注解将被编译器丢弃。
2)Retention.CLASS:注解在class文件中可以使用,但是会被VM丢弃。
3)Retention.RUNTIME:虚拟机在运行期将保留注解,此时可以通过反射机制读取注解中的信息并进行相关操作。
(3)@Documented:将此注解包含javadoc中。
(4)@Inherited:允许子类继承父类中的注解。当用户查询子类的注解且子类没有生命注解,此时会查询父类中的注解。
(5)@Repeatable:声明注解可以在同一个声明的地方重复多次使用,该注解是在java8中引进的。
2.java内置的标准注解
(1)@Deprecated:标注代码已经被遗弃了,不推荐被使用。在使用@Deprecated注解时,同时应该在注释中使用@deprecated说明被遗弃的原因以及推荐使用什么作为替代。
如果使用被该注解标记的代码,则编译器会产生警告信息。
(2)@Override:用于子类方法上,表示该方法是重写父类的方法。如果该方法签名和父类方法不同,则编译器会报错。
(3)@SuppressWarning:关闭编译器的警告信息。
1)取值为unchecked:关闭泛型产生的类型检查警告。
2)取值为deprecation:关闭使用已经被遗弃的代码产生的警告。
(4)@FunctionalInterface:表示声明的接口是功能性接口。
(5)@SafeVarargs:用于方法和构造器时,表示不存在对参数不安全的操作。改标签同时也会关闭unchecked警告。