Java注解

Java注解

注解,类似于注释,不过不同于注释,注释是给程序员(媛)看的,而注解则是给计算机看的,用于在需要做特定处理的位置做标记,并可以传入一些参数来做更复杂的进一步操作,注解可以位于类、成员变量、方法等上方。

注解的基本结构

@Documented                         //元注解,用于对注解做进一步说明
@Retention(RetentionPolicy.RUNTIME) //元注解,用于对注解做进一步说明
@Target(ElementType.ANNOTATION_TYPE)//元注解,用于对注解做进一步说明
public @interface Target {
    //不同于一般的类和接口,该处的声明分别代表参数类型和参数名
    //传参方式:单值:value=ElementType.METHOD,多值:value={ElementType.CONSTRUCTOR, ElementType.FIELD})
    ElementType[] value();
}

需要注意的地方

  1. 在定义了参数后,使用注解时就必须给参数赋值,可以在参数后通过增加default指定默认值的方式来避免不必要的手动赋值
  2. 当注解中只有一个参数时,并且参数名为value时,value可以省略不写
  3. 数组赋值时,使用{}包裹,如果数组中只有一个值,则{}可以省略
  4. 参数类型可以有的几种取值:基本数据类型、String、枚举、注解以及对应类型的数组

元注解

元注解用于对注解作出进一步解释的注解,常用的有@Target、@Retention、@Documented、@Inherited等,下面对注解进行介绍

@Target

@Target注解用于描述注解的使用范围,常用的有以下值:

ElementType.TYPE    //类,接口,枚举等
ElementType.FIELD   //成员变量
ElementType.METHOD  //方法

@Retention

@retention注解用于设置注解的保留策略,有以下三种取值:

RetentionPolicy.SOURCE  //该类型的注解在编译时会被丢弃,即只保存在源码中
RetentionPolicy.CLASS   //该类型的注解会被编译器保留到字节码文件中,但不会在运行时被JVM保留,该配置是默认的策略
RetentionPolicy.RUNTIME //该类型的注解不仅会被编译器保留包字节码文件中,还会在JVM运行时保留,所以该类型的注解可以通过反射读取,一般自定义注解使用方式

@Documented

@documented注释的部分,在使用javac生成API文档时会成为API的一部分

//上述基本结构举例的@Target注解上就有元注解@Documented,在API文档中查看@Target的部分就会把注解部分也加入其中,如下所示
@Documented
 @Retention(value=RUNTIME)
 @Target(value=ANNOTATION_TYPE)
public @interface Target

@Inherited

@Inherited注解标记的注解,只有在类上才有效(只有类有继承关系),被该注解标记的类,其子类会自动继承父类的所有注解,以下使用自定义注解来演示该注解的使用:

//注解的定义
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})  //可以在类,成员变量,方法上使用
@Retention(RetentionPolicy.RUNTIME)                                 //保留策略为RUNTIME,可以在JVM中运行时被加载
@Inherited
public @interface Mango {
    String value(); //不带默认值的value参数,使用时必须手动赋值

    String[] attr() default {"默认值1", "默认值2"};//带默认值参数attr,使用时可以不必手动赋值
}
//父类定义
@Mango("value属性值")
public class Father {
}
//子类的定义
public class Children extends Father{
    public static void main(String[] args) {
        Mango annotation = Children.class.getAnnotation(Mango.class);
        System.out.println(annotation.attr()[1]);
        System.out.println(annotation.value());
    }
}
//对应的运行结果值
默认值2
value属性值

常见的内置注解

@Override

@Override是一个空接口,用于标记,最后会用一个案例来阐明标记的意义
@Override重写父类的方法,被该注解修饰的方法如果没有重写父类的方法,编译器会报异常

@Deprecated

@Deprecated也是一个空接口,用于遗弃该方法,被该注解修饰的方法通常是因为它很危险或存在更好的选择,而且可能在未来会被删除,一般不鼓励程序员再去使用该方法,当然,如果方法依旧存在,也是可以调用的,不过会提出警告,如果不想理会警告,可以使用@SuppressWarnings("deprecation")来镇压警告信息

@SuppressWarnings

@SuppressWarnings接口用于抑制编译时的警告信息,有如下参数可以使用

deprecation:使用了过时的类或方法的警告
unchecked:执行了未检查的转换时的警告,如使用集合是未指定泛型
fallthrough:当在switch语句使用时发生case穿透
path:在类路径、源文件路径等中有不存在路径的警告
serial:当在可序列化的类上缺少serialVersionUID定义时的警告
finally:任何finally子句不能完成时的警告
unuse:变量定义后未被使用
resource:资源对象未释放
all:关于以上所有情况的警告

放在最后,一个很有用的注解使用案例

注解的定义

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Transactional {
}

主代码

public class TestServiceImpl {
    @Transactional
    public String getSomeMsg() {
        /* some code */
        System.out.println("some operation");
        return "result";
    }

    public static void main(String[] args) throws Exception {
        Class<TestServiceImpl> Service = (Class<TestServiceImpl>) Class.forName("com.mango.test.TestServiceImpl");
        TestServiceImpl testServiceImpl = Service.newInstance();
        for (Method method : Service.getMethods()) {
            if (method.isAnnotationPresent(Transactional.class)) {
                System.out.println("事务开启");
                method.invoke(testServiceImpl);
                System.out.println("事务提交");
            }
        }
    }
}

运行结果

事务开启
some operation
事务提交

如果对你有帮助,点个赞,或者打个赏吧,嘿嘿
整理不易,请尊重博主的劳动成果

posted @ 2020-04-22 14:56  Mango_SF  阅读(188)  评论(0编辑  收藏  举报