Java之 注解
什么是注解
概念
An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.
作用
Annotations have a number of uses, among them:
Information for the compiler — Annotations can be used by the compiler to detect errors or suppress warnings.
Compile-time and deployment-time processing — Software tools can process annotation information to generate code, XML files, and so forth.
Runtime processing — Some annotations are available to be examined at runtime.
-
标记,用于告诉编译器一些信息
-
编译时动态处理,如动态生成代码
-
运行时动态处理,如得到注解信息
参考:
Java Annotation
Java Reflection - Annotations
注解的使用
格式
一个注解由一个@符号后面跟字符串组成,例如:
@Entity
java注解里面一般包含一些元素,这些元素类似于属性或者参数,可以用来设置值,比如我们有一个包含两个元素的@Entity注解:
@Entity(name="mzw", job="码农")
该注解有两个元素,name和job,分别赋予了元素值。
位置
注解可以用于描述一个类、接口、方法、方法参数、字段、局部变量等。
- 方法:
@Override
public void mySuperMethod() { ... }
@SuppressWarnings(value = "unchecked")
public void myMethod() { ... }
- 类
@Author(
name = "zphuan",
date = "3/24/2017"
)
public class MyClass() { ... }
- 方法参数
pulic void myMethod(@RequestParam String s){ ... }
- 局部变量
@Autowired
private MyClass myClass;
细节
-
如果注解没有参数,则不用加参数,如:@Override
-
如果注解只有一个参数,那么参数名字可以省略,如:
@SuppressWarnings("unchecked")
public void myMethod() { ... }
- 一个地方可以使用多个注解,如:
@Author(name = "Jane Doe")
@EBook
public class MyClass { ... }
- 可以重复使用注解,不过只有在java SE 8 才支持。比如:
@Author(name = "Jane Doe")
@Author(name = "John Smith")
public class MyClass { ... }
表明有两个人对该类进行了代码编写。
内置注解
java本身提供了三个内置注解:
- @Override
注解是一个编译时注解,它主要用在一个子类的方法中,当被注解的子类的方法在父类中找不到与之匹配的方法时,编译器会报错。 - @Deprecated
可以用来描述一个类、方法或者字段,表示java不赞成使用这些被描述的对象,如果我们使用了这些类、方法或者字段,编译器会给我们警告。 - @SuppressWarnings
作用是使编译器忽略掉编译器警告。比如,如果我们的一个方法调用了一个@Deprecated方法,或者做了一个不安全的类型转换,此时编译器会生成一个警告。如果我们不想看到这些警告,我们就可以使用@SuppressWarnings注解忽略掉这些警告。
自定义注解
元注解
元注解就是用来描述注解的注解,在java里面有下面几个元注解:
- @Documented
作用是告诉JavaDoc工具,当前注解本身也要显示在Java Doc中。 - @Retention
用来定义注解的范围,有下面三个范围:
- RetentionPolicy.SOURCE
注解只存在于源码中,不会存在于.class文件中,在编译时会被忽略掉。 - RetentionPolicy.CLASS
注解只存在于.class文件中,在编译期有效,但是在运行期会被忽略掉,这也是默认范围。 - RetentionPolicy.RUNTIME
在运行期有效,JVM在运行期通过反射获得注解信息。
- @Target
用于指定注解作用于java的哪些元素,未标注则表示可修饰所有。
ElementType.ANNOTATION_TYPE Annotation type declaration
ElementType.CONSTRUCTOR Constructor declaration
ElementType.FIELD Field declaration (includes enum constants)
ElementType.LOCAL_VARIABLE Local variable declaration
ElementType.METHOD Method declaration
ElementType.PACKAGE Package declaration.
ElementType.PARAMETER Parameter declaration
ElementType.TYPE Class, interface (including annotation type), or enum declaration
- @Inherited
注解表示当前注解会被注解类的子类继承。
参考:
Java Doc
注解解析
运行时注解
首先,先定义一个注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public String job();
}
上面通过元注解的定义,可以看出来自定义的注解是运行时注解,可以修饰所有的类型。
类注解
@MyAnnotation(name = "mzw", job = "给类添加了一个注解")
public class TestAnnotation { ... }
现在当程序运行起来的时候我想要获取到TestAnnotation中的@MyAnnotation的注解信息:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyAnnotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);
Log.e("mzw", "name == " + annotation.name());
Log.e("mzw", "value == " + annotation.value());
}
}
运行后执行结果为:
24603-24603/demo.remer.myannotation E/mzw: name == mzw
24603-24603/demo.remer.myannotation E/mzw: value == 给类添加了一个注解
方法注解
public class TestAnnotation {
@MyAnnotation(name = "mzw", value = "给方法添加了一个注解")
public void test(){
}
}
当程序运行时,可以获取到类中test方法注解的信息:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Class clazz = Class.forName(TestAnnotation.class.getName());
for (Method method : clazz.getMethods()) {
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
if (annotation != null) {
Log.e("mzw", "name === " + method.getName() + "||" + annotation.name());
Log.e("mzw", "value == " + method.getName() + "||" + annotation.value());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行执行的结果为:
20791-20791/demo.remer.myannotation E/mzw: name === test||mzw
20791-20791/demo.remer.myannotation E/mzw: value == test||给方法添加了一个注解
参数注解
public class TestAnnotation {
public static void test(@MyAnnotation(name = "参数", value = "参数上的注解") String parameter){ ... }
}
运行程序,可以获取到方法上的参数注解信息:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try {
Class clazz = Class.forName(TestAnnotation.class.getName());
for (Method method : clazz.getMethods()) {
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Class[] parameterTypes = method.getParameterTypes();
int i = 0;
for (Annotation[] annotations : parameterAnnotations) {
Class parameterType = parameterTypes[i++];
for (Annotation annotation : annotations) {
if (annotation instanceof MyAnnotation) {
MyAnnotation myAnnotation = (MyAnnotation) annotation;
Log.e("mzw", "param === " + parameterType.getName());
Log.e("mzw", "name === " + myAnnotation.name());
Log.e("mzw", "value === " + myAnnotation.value());
}
}
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
运行执行的结果为:
17392-17392/demo.remer.myannotation E/mzw: param === java.lang.String
17392-17392/demo.remer.myannotation E/mzw: name === 参数
17392-17392/demo.remer.myannotation E/mzw: value === 参数上的注解
注意
isAnnotationPresent(AnnotationName.class) 可以判断Target是否被某个注解修饰