• 0035 Java学习笔记-注解


    什么是注解

    • 注解可以看作类的第6大要素(成员变量、构造器、方法、代码块、内部类)
    • 注解有点像修饰符,可以修饰一些程序要素:类、接口、变量、方法、局部变量等等
    • 注解要和对应的配套工具(APT:Annotation Processing Tool)一起使用,APT会对含有注解进行一些处理
    • 比如API文档里面,有些方法下边的“@Deprecated”,就是一个注解,它表示这个方法已经过时,使用的时候会收到警告
    • 注解完全不影响程序的功能

    元注解

    • 元注解有6个,位于java.lang.annotation包下
    • @Retention
      • 只能修饰注解
      • 用于指定被修饰的注解,可以保留到什么时间
      • @Retention只有一个元素:value,是RetentionPolicy类型,这是个枚举类,只有如下三个值
        • RetentionPolicy.SOURCE:注解只保留在源代码中,编译阶段即被丢弃
        • RetentionPolicy.CLASS:保留在class文件中,程序运行时,JVM不能获取到该注解
        • RetentionPolicy.RUNTIME:保留在class文件中,程序运行时,可以通过反射获得该注解
    • @Target
      • 只能修饰注解
      • 用于指定被修饰的注解,可以用于修饰哪些程序元素
      • @Target只有一个元素:value,是ElementType[]类型,ElementType也是个枚举类,只有如下十个值
        • ElementType.TYPE:表示被修饰的注解可以修饰类、接口、注解、枚举
        • ElementType.FIELD:只能修饰成员变量
        • ElementType.METHOD:只能修饰方法
        • ElementType.PARAMETER:可以修饰参数
        • ElementType.CONSTRUCTOR:只能修饰构造器
        • ElementType.LOCAL_VARIBLE:只能修饰局部变量
        • ElementType.ANNOTATION_TYPE:只能修饰注解
        • ElementType.PACKAGE:只能修饰包
        • ElementType.TYPE_USE:since 1.8,表示注解能写在使用类型变量的语句中
        • ElementType.TYPE_PARAMETER:since 1.8,表示注解能写在类型变量的声明语句中
    • @Documented
      • 修饰注解,该注解将被javadoc提取进入文档
      • 该元注解没有元素
    • @Inherited
      • 修饰注解,表示该注解具有继承性
      • 比如:一个父类使用了一个注解X修饰,而X注解在定义时用了@Inherited修饰,那么子类自动被X修饰
    • @Repeatable
      • 用于修饰一个注解,表示该注解可以用于重复注解
      • 包含一个变量value,是Annotation的Class类型
    • @Native

    基本注解

    • 基本注解有5个,位于java.lang包下
    • @Override
      • 只能修饰方法;保留在源代码阶段
      • 告诉编译器,被该修饰符修饰的方法是在重写父类的方法,如果父类中没有相同签名的方法,那么会发生错误
    • @Deprecated
      • 修饰构造器、成员变量、局部变量、方法、包、参数、类、注释、枚举;保留到运行阶段;javadoc提取
      • 表示该元素已过时,其他地方使用这些元素时,编译器会给出警告
    • @SuppressWarnings
      • 修饰类、接口、注解、枚举、成员变量、方法、参数、构造方法、局部变量;保留在源代码阶段;
      • 只有一个变量value,类型为String[]
      • 被修饰的程序元素及子元素取消value指定的编译器警告
    • @SafeVarargs
      • 修饰构造器、方法;保留在运行阶段;javadoc提取
      • 专门修饰会引发“堆污染”警告的方法或者构造器
      • since 1.7
    • @FunctionalInterface
      • 只能修饰接口;保留到运行阶段;javadoc提取
      • 告诉编译器严格检查,该接口为函数式接口
      • since 1.8

    自定义注解

    • 自定义注解跟定义接口类似,只是用“@interface”关键字替换“interface”
    • 可以用一些元注解修饰即可,对于保留时间,如果不写@Target,那么默认是修饰任何程序要素
    • 可以包含变量
    • 比如@Deprecated的源代码是这样的
    package java.lang;
    
    import java.lang.annotation.*;
    import static java.lang.annotation.ElementType.*;
    
    @Documented                                          //元注解:表示该注解会被javadoc提取到文档中
    @Retention(RetentionPolicy.RUNTIME)                  //元注解:保留到运行阶段
    @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})  //元注解:可以修饰的程序元素
    public @interface Deprecated {
    }
    
    • 再比如@SuppressWarnings的源代码
    package java.lang;
    
    import java.lang.annotation.*;
    import static java.lang.annotation.ElementType.*;
    
    @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    @Retention(RetentionPolicy.SOURCE)
    public @interface SuppressWarnings {
    	String[] value();                       //可以包含变量,String[]是该变量的类型
    }
    
    • 包含变量的时候,使用时就不能只写注解名称,还得写变量的值,比如:
    @SuppressWarnings(value="unchecked")
    //如果只有一个变量,那么可以省略变量名:
    @SuppressWarnings("unchecked")
    
    • 不写变量名和值,那么该注解在定义的时候,就得定义默认值,用default关键字,比如
    @Target({TYPE, FIELD})                   //只有一个变量,省略变量名
    @Retention(RetentionPolicy.CLASS)        //只有一个变量,省略变量名
    public @interface Test{
    	String name() default "Java";        //用default指定默认值
    	int age() default 18;                //用default指定默认值
    }
    
    • 实际上,自定义注解默认都是继承了java.lang.annotation.Annotation接口的,见示例:
    package testpack;
    public class Test1  { 
        public static void main(String[] args){ 
        	Class clazz=Test.class;
        	Class[] is=clazz.getInterfaces();
        	for (Class i:is) {
        		System.out.println(i);    //输出:interface java.lang.annotation.Annotation
        	}
        }
    }
    @interface Test{
    	
    }
    

    注解的分类

    • 标记注解:不包含成员变量
    • 元数据注解:包含成员变量

    获取程序元素的注解信息

    • 光有注解没用,还得有对应的工具来处理,要处理,得先获取注解信息
    • 获取到注解信息的前提是,注解能保留到"获取"这个操作的时候
    • 在文章0033 Java学习笔记-反射-初步1中提到,通过反射可以获取一个类的注解信息,有六个方法,其实这些方法都来自于一个接口:java.lang.reflect.AnnotatedElement,Class是它的实现类之一
    • java.lang.reflect.AnnotatedElement是个接口,表示程序中可以接受注解的程序元素,主要有如下几个实现类
      • Package
      • Class
      • Filed
      • Constructor
      • Method
      • Parameter
    • 以上这些类都包含0033 Java学习笔记-反射-初步1中关于获取注解的那6个方法,
    • 除以上6个方法外,还有一个方法用于判断程序元素上是否存在指定类型的注解:boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
    • 见示例:
    package testpack;
    
    import java.lang.annotation.Annotation;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Test(name="Java",age=18)
    public class Test1  { 
        public static void main(String[] args){ 
        	Class clazz=Test1.class;
        	Annotation a=clazz.getAnnotation(Test.class);    //获取对应类的Test类型的注解
        	System.out.println(a);
        	if (a instanceof Test){
        		System.out.println(((Test)a).name());        //强制类型转型后获取name的值
        		System.out.println(((Test)a).age());         //强制类型转型后获取age的值
        	}
        }
    }
    
    @Retention(RetentionPolicy.RUNTIME)                //保留到运行时,这条很重要
    @interface Test{
    	public String name();                          //定义两个变量
    	public int age();
    }
    
    

    重复注解

    • 重复注解是Java8新增的功能
    • 重复注解是值:用多个相同类型的注解修饰同一个程序元素
    • 使用重复注解要分3步走:
      • 定义一个注解,并用@Repeatable修饰
      • 再定义一个该注解的容器注解
      • 使用重复注解
    • 示例:
    package testpack;
    
    import java.lang.annotation.Annotation;
    import java.lang.annotation.Repeatable;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    
    @Test(name="C++",age=30)
    @Test(name="Java",age=18)                    //使用了两个相同类型的注解
    public class Test1  { 
        public static void main(String[] args){ 
        	Class clazz=Test1.class;
        	Annotation[] as=clazz.getAnnotations();
        	for (Annotation a:as){
        		System.out.println(a);
        		//输出:@testpack.Tests(value=[@testpack.Test(name=C++, age=30), @testpack.Test(name=Java, age=18)])  
        		//其实还是只有一个注解,就是Tests这个容器注解
    
        	}
        	
        }
    }
    @Repeatable(Tests.class)               //用@Repeatable修饰
    @Retention(RetentionPolicy.RUNTIME)
    @interface Test{                       //定义Test注解
    	public String name();
    	public int age();
    }
    @Retention(RetentionPolicy.RUNTIME)    //容器注解的保留时间不能早于其对应的注解
    @interface Tests{                      //定义Test的容器注解Tests
    	Test[] value();                    //容器注解的变量
    }
    
    

    类型注解

    • 类型注解也是Java8新增功能
    • Java8以前的注解只能用在一些特定的程序元素上,
    • ElementType.TYPE_PARAMETER:表示注解能写在类型变量的声明语句中
    • ElementType.TYPE_USE:表示注解能写在使用类型变量的语句中
    • 对该部分内容没什么理解,更详细的内容见:Java 8的类型注解:工具和机会

    APT工具

    • APT(Annotation Processing Tool):一种注解处理工具,用于对源代码文件进行检测,找出特定的注解信息,然后进行特别的处理
    • 比如可以在编译源代码的同时,生成一些附属的描述文件,
    • 在用javac.exe编译源代码时,可以用“-processor”选项指定注解处理器
    • 注解处理器一般实现javax.annotation.processing.Processor接口或者继承AbstractProcessor抽象类
    • 一个注解处理器,可以处理一个或多个注解

    其他

  • 相关阅读:
    Windowsforms 中对文件操作
    ADO.net增删改的使用
    ADO.net数据访问
    可空类型
    FineUI 页面跳转
    ASP.NET页面之间传递值的几种方式
    C# Find() 与 FindAll()方法的使用
    在Sql中将 varchar 值 '1,2,3,4,5,6' 转换成数据类型 int
    DataSet、DataTable、DataRow、DataColumn区别及使用实例
    C#中如何排除/过滤/清空/删除掉字符串数组中的空字符串
  • 原文地址:https://www.cnblogs.com/sonng/p/6121341.html
Copyright © 2020-2023  润新知