1. Java注解
注解:Annotation
- 位于源码中(代码/注释/注解),使用其他工具进行处理的标签
- 注解用来修饰程序的元素,但不会对被修饰的对象有直接的影响
- 只有通过某种配套的工具才会对注解信息进行访问和处理
主要用途:
- 提供信息给编译器/IDE工具
- 可用于其他工具来产生额外的代码/配置文件等
- 有一些注解可在程序运行时访问,增加程序的动态性
1.1 Java 普通注解
注解 | 含义 | 用途 |
---|---|---|
@Override | 继承和覆写 | 修饰方法,检查该方法是父类的方法;强制该函数代码必须符合父类中该方法的定义;避免代码错误 |
@Deprecated | 废弃 | 标注为废除,建议程序员不再使用这个类/元素/包 |
@SuppressWarnings | 压制警告 | 压制各种不同类型的警告信息,使得编译器不显示警告;警告类型名称是编译器/IDE工具自己定义的,Java规范没有强制要求 |
@SafeVarargs | 不会对不定项参数做危险操作 | |
@FunctionInterface | 声明功能性接口 |
- @ SuppressWarnings
– @SuppressWarnings(“unchecked”) 忽略unchecked警告信息
– @SuppressWarnings(“deprecated”) 忽略过时方法的警告信息
– @SuppressWarnings({“unchecked”,“deprecated”}) 忽略两种警告
信息
– @ SuppressWarnings(values={“unchecked”,“deprecated”}) 同上
– @ SuppressWarnings( “all”) 忽略所有的警告信息
– 其他的警告类型
• all,忽略所有的警告
• cast,忽略类转型警告
• serial,忽略实现Serializable接口的,没有定义serialVersionUID
• 使用javac -X 可以看当前的编译器使用哪些警告类型
1.2 Java 自定义注解
– Java是通过反射,来获取注解信息并运行注解
– 扩展java.lang.annotation.Annotation注解接口
– 注解可以包括的类型
- 8种基本类型(int/short/long/float/double/byte/char/boolean)
- String
- Class
- enum类型
- 注解类型
- 由前面类型组成的数组
@interface
public @interface BugReport {
enum Status {UNCONFIRMED, CONFIRMED, FIXED, NOTABUG};
boolean showStopper() default true;
String assiganedTo() default "[none]";
Status status() default Status.UNCONFIRMED;
String[] reportedBy();
}
Java自定义注解
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
//表示该注解会保留在class文件中
@Target(ElementType.METHOD)
//表示该注解只能用于方法
public @interface SingleTest {
int value() default 0;
//String para();
}
Java注解的运行与使用
public class Foo {
@SingleTest(1)
public static void m1(int a) {
if(a<0)
{
throw new RuntimeException("Crash");
}
}
public static void m2() {
}
@SingleTest(value=-2)
public static void m3(int a) {
if(a<0)
{
throw new RuntimeException("Crash");
}
}
}
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
public class Main {
public static void main(String[] args) throws Exception {
int passed = 0, failed = 0;
String className = "annotations.single.Foo";
for (Method m : Class.forName(className).getMethods()) {
if (m.isAnnotationPresent(SingleTest.class)) {//判读是否有SingleTest注解
System.out.println(m.getName());
SingleTest st = m.getAnnotation(SingleTest.class);
try {
m.invoke(null,st.value());//传递注解的参数
passed++;
} catch (Throwable ex) {
System.out.printf("Test %s failed: %s %n", m, ex.getCause());
failed++;
}
}
}
System.out.printf("Passed: %d, Failed %d%n", passed, failed);
}
}
1.3 Java 元注解
元注解:修饰注解的注解
– 一般自定义注解时使用
元注解 | 注解说明 | |
---|---|---|
@Target | 设置目标范围 | |
@Retention | 注解的保存范围 | |
@Inherited | 注解可继承 | |
@Repeatable | 此注解可以重复修饰 | |
@Document | 注解可以被Javadoc工具所解析 |
Retention(保留)
–这个注解用来修饰其他注解的存在范围
–示例:@Retention(RetentionPolicy.RUNTIME)
- RetentionPolicy.SOURCE 注解仅存在源码,不在class文件。
- RetentionPolicy.CLASS 这是默认的注解保留策略。注解存在于.class文件,但是不能被JVM加载。
- RetentionPolicy.RUNTIME 这种策略下,注解可以被JVM运行时访问到。通常情况下,可以结合反射来做一些事情。
Target
–限定目标注解作用于什么位置
–@Target({ElementType.METHOD})
–ElementType.ANNOTATION_TYPE(注:修饰注解)
–ElementType.CONSTRUCTOR
–ElementType.FIELD
–ElementType.LOCAL_VARIABLE
–ElementType.METHOD
–ElementType.PACKAGE
–ElementType.PARAMETER
–ElementType.TYPE(注:任何类型,即上面的的类型都可以修饰)
Inherited
–普通的注解没有继承功能(子类继承父类,不会继承父类的注解)
–@Inherited 让一个类和它的子类都包含某个注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritAnnotation {
}
@InheritAnnotation
public class InheritFather {
}
//子类继承了父类的@InheritAnnotation注解
public class InheritSon extends InheritFather{
}
Repeatable
– 表示被修饰的注解可以重复应用标注
– 需要定义注解和容器注解
RepeatableAnnotation //重复元注解
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RepeatableAnnotations.class)
public @interface RepeatableAnnotation {
int a() default 0;
int b() default 0;
int c() default 0;
}
RepeatableAnnotations //重复元注解容器
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatableAnnotations {
RepeatableAnnotation[] value();
}
Student //方法类
public class Student {
@RepeatableAnnotation(a=1,b=2,c=3)
@RepeatableAnnotation(a=1,b=2,c=4)
public static void add(int a, int b, int c)
{
if(c != a+b)
{
throw new ArithmeticException("Wrong");
}
}
}
Main
public static void main(String[] a) throws Exception
{
String className = "repeatable.Student";
for (Method m : Class.forName(className).getMethods())
{
if (m.isAnnotationPresent(RepeatableAnnotations.class))
{
RepeatableAnnotation[] annos = m.getAnnotationsByType(RepeatableAnnotation.class);
for (RepeatableAnnotation anno : annos)
{
System.out.println(anno.a() + "," + anno.b() + "," + anno.c());
try
{
m.invoke(null,anno.a(),anno.b(),anno.c());
} catch (Throwable ex) {
System.out.printf("Test %s failed: %s %n", m, ex.getCause());
}
}
}
}
}
Documented
–指明这个注解可以被Javadoc工具解析,形成帮助文档
2. Java 注解解析
RetentionPolicy.RUNTIME:注解在class文件中,被JVM加载,可用反射解析注解
- Class.getAnnotations() 获取注解数组
- Class.isAnnotation() 是否有注解
- Class.isAnnotationPresent(Class annotationClass) 是否是某个注解
- Method/Field/Constructor.getAnnotations()/isAnnotationPresent(Class annotationClass)
RetentionPolicy.CLASS:注解在class文件中,但没有被JVM加载
– 只能使用字节码工具进行特殊处理
RetentionPolicy.SOURCEC:注解在java文件中,只有在源码级别进行注解处理
– Java提供注解处理器来解析带注解的源码,产生新的文件
3. Java注解应用
– Junit
– Spring,Springboot
– …各种应用框架,注解能够简化配置文件,提高程序灵活性
注解的优缺点:
优点:
1、节省配置,减少配置文件大小
2、编译时即可查看正确与否,提高效率
缺点:
1、增加了程序的耦合性,因为注解保存在class文件中,而且比较分散
2、若要对配置进行修改需要重新编译