Java注解小记

本文介绍了Java注解这一JDK1.5后的新特性,它提升了Java语言表达能力。先阐述了Java内置的三个注解,接着详细讲解自定义注解,包括注解定义(四个元注解、注解参数、注解特点),还说明了注解实现(注解处理器),可通过反射实现并在运行时查看注解信息。

java注解是jdk1.5以后新出的特性,注解提升了Java语言的表达能力,有效地实现了应用功能和底层功能的分离,框架/库的程序员可以专注于底层实现。

1、Java内置注解

主要有三个:

@Override:用于标明此方法覆盖了父类的方法

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Deprecated:用于标明已经过时的方法或类,源码如下

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

@SuppressWarnnings:用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

value是一个数组,可以有如下值:

  • deprecation:使用了不赞成使用的类或方法时的警告;
  • unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型;
  • fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
  • path:在类路径、源文件路径等中有不存在的路径时的警告;
  • serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
  • finally:任何 finally 子句不能正常完成时的警告;
  • all:关于以上所有情况的警告。

三个综合使用的示例:

 1 //注明该类已过时,不建议使用
 2 @Deprecated
 3 class A{
 4     public void A(){ }
 5 
 6     //注明该方法已过时,不建议使用
 7     @Deprecated()
 8     public void B(){ }
 9 }
10 
11 class B extends A{
12 
13     @Override //标明覆盖父类A的A方法
14     public void A() {
15         super.A();
16     }
17 
18     //去掉检测警告
19     @SuppressWarnings({"uncheck","deprecation"})
20     public void C(){ } 
21     //去掉检测警告
22     @SuppressWarnings("uncheck")
23     public void D(){ }
24 }
View Code

 

2、自定义注解

2.1、注解定义

Java提供了一些定义好的注解如@SuppressWarnings、@Override等。也可以借助元注解来自定义注解,其格式示例如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
@Documented
@Inherited
public @interface Mark {
}

2.1.1、四个元注解

@Target,指定注解的应用目标,如@Target(ElementType.METHOD)。目标可以是多个,用{}表示,如@Target({TYPE, FIELD, METHOD, PARAMETER}),若未声明@Target,默认为适用于所有类型。目标是个枚举值ElementType,可以是:

  • TYPE:表示类、接口(包括注解),或者枚举声明
  • FIELD:字段,包括枚举常量
  • METHOD:方法
  • PARAMETER:方法中的参数
  • CONSTRUCTOR:构造方法
  • LOCAL_VARIABLE:本地变量
  • ANNOTATION_TYPE:注解类型
  • PACKAGE:包
  •  TYPE_PARAMETER:表示注解可以用于标注类型参数(java 1.8新加入),如class D<@Parameter T> { }
  • TYPE_USE:表示注解可以用于标注任意类型(不包括class)(java 1.8新加入),如用于标注父类或接口:class Image implements @Rectangular Shape { }

 @Retention,表示注解信息保留到什么时候。若未声明@Retention,则默认为CLASS。Retention取值只能有一个,类型为RetentionPolicy,它是一个枚举,有三个取值:

  • SOURCE:只在源码中保留,编译器将代码编译为字节码后就会丢掉注解信息。如@Override。
  • CLASS:保留到字节码文件中,但JVM将class文件加载到内存时注解丢弃。
  • RUNTIME:一直保留到运行时,故能在运行时被JVM或其他使用反射机制的代码所读取和使用。如@Deprecated、Spring中的@Controller、@Autowired、@RequestMapping等。

@Documented,表示注解包含到Javadoc中,即被修饰者在javadoc中仍然带着该注解。若未声明则默认不被包含
@Inherited,表示子类是否会继承父类的注解。若未声明则默认不会被继承。注:这里说的继承是指被注解修饰的类的继承。注解本身是不支持继承的,因此定义注解时不能使用关键字extends来继承某个注解

另:@Repeatable,Java1.8新增了@Repeatable元注解,以允许对同一个位置重复使用相同注解。在Java1.8前没法对同一个元素重复使用同一个注解,要实现该效果只能为注解定义一个数组元素以接收多个值。

//Java8前无法这样使用
@FilterPath("/web/update")
@FilterPath("/web/add")
public class A {}



//只能为@FilePath注解定义一个数组元素
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FilterPath {
    String [] value();
}

//使用
@FilterPath({"/update","/add"})
public class A { }
Java1.8之前
//使用Java8新增@Repeatable原注解
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(FilterPaths.class)//参数指明接收的注解class
public @interface FilterPath {
    String  value();
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface FilterPaths {
    FilterPath[] value();
}

//使用案例
@FilterPath("/web/update")
@FilterPath("/web/add")
@FilterPath("/web/delete")
class AA{ }
Java1.8之后借助@Repeatable元注解

 

 

2.1.2、注解参数

可以为注解定义一些参数,定义方式为:在注解内定义一些方法,方法返回值类型表示参数的类型。

参数的类型不是什么都可以的,合法的类型有:8钟基本类型(不允许使用包装类型)、String、Class、枚举(enum)、注解(Annotation)、以及这些类型的数组。倘若使用了其他数据类型,编译器将会丢出一个编译错误。

如对于如下注解,可以这样使用:使用: @SuppressWarnings(value={"deprecation","unused"}) 

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

注:

  • 当注解只有一个参数,且名称为value时,提供参数值时可以省略"value=",如@SuppressWarnings({"deprecation","unused"})
  • 参数定义时可以使用default指定一个默认值。
  • 元素不能有不确定的值:必须要么具有默认值,要么在使用注解时提供元素的值,且值不能为null(无论是在源代码中声明,还是在注解接口中定义默认值,都不能以null作为值)。

2.1.3、注解特点

注解的定义不支持继承:无法使用关键字extends来继承某个@interface,但注解在编译后,编译器会让注解自动继承java.lang.annotation.Annotation接口。

import java.lang.annotation.Annotation;
//反编译后的代码
public interface DBTable extends Annotation
{
    public abstract String name();
}

虽然注解的定义不能继承,但可以通过类似组合的写法来继承其他注解的功能,如RestController就拥有了@Controller、@ResponseBoddy的功能(另外可以发现上面的元注解也是用了其组合了其他元注解以拥有相应的功能),其定义如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller
@ResponseBody
public @interface RestController {

    /**
     * The value may indicate a suggestion for a logical component name,
     * to be turned into a Spring bean in case of an autodetected component.
     * @return the suggested component name, if any (or empty String otherwise)
     * @since 4.0.1
     */
    @AliasFor(annotation = Controller.class)
    String value() default "";

}

 

 

2.2、注解实现(注解处理器)

通过反射来实现注解处理器。

查看注解

可以在运行时(即@Retention为RetentionPolicy.RUNTIME的注解)查看注解:与反射相关的类(Class、Field、Method、Constructor)中定义了一些方法:如Student.class.getAnnotation,可以利用反射机制在运行时查看和利用注解信息。方法如:

    //获取所有的注解
    public Annotation[] getAnnotations()
    //获取所有本元素上直接声明的注解,忽略inherited来的
    public Annotation[] getDeclaredAnnotations()
    //获取指定类型的注解,没有返回null
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) 
    //判断是否有指定类型的注解
    public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

 

3、参考资料

  1. 注解——老马说编程
  2. 深入理解JavaScript注解类型(推荐)

 

转载于:https://www.cnblogs.com/z-sm/p/9178492.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值