常用Java注解

注解
理解注解(Annotation):
用法:@注解
注解本身是添加到Java源程序上,但它本身对Java程序并不会产生影响,它只用于提供额外的信息,它需要额外的注解处理工具(APT)来读取,并根据注解做进一步的处理。
——在极端情况下,即使对于同一个注解,在不同的注解处理工具中,它会产生不同的作用。
【总结】注解是添加到源程序中的额外信息,而注解起什么作用,完全取决于注解的处理工具(APT)
JDK在java.lang包下,Java内置几个常用注解:这几个常用注解,由于是Java本身提供的,因此java的编译器(javac)默认会提取、并处理这些注解
1、@Override:要求被修饰的方法必须是重写父类、接口的方法,否则报错。
2、@Deprecated(Since,forRemoval):用于标注某个类、某个方法、成员变量…等程序单元被标记为过时。@Deprecated比@deprecated更方便,多了如下两个属性:
forRemoval:指定被修饰的程序单元将来是否会被删除true or false。
Since:指定被修饰的程序单元将会在哪个版本中被标记为过时
用法:@Deprecated(Since=”9”,forRemoval=true)指定版本9过期,将来被删除。
一旦使用@Deprecated注解修饰了某个程序单元,那么只要其他程序使用该程序单元都会受到警告。
3、@SuppressWarnings:用于去掉编译器的警告。只要java程序有警告,如果能确定程序确实没问题——那么可以使用该注解来取消警告。
滥用这个注解会导致负面影响!
建议:当用该注解去掉警告时,一定要先认真检查源代码,确保程序没问题才谨慎使用
4、堆污染警告与@SafeVarargs:vavargs是个数可变的参数,个数可变的参数的本质是数组。
Java允许声明泛型数组,但不能创建泛型数组,除非使用通配符。因此,如果方法中个数可变的参数带了泛型,程序就会引发“堆污染”警告。
把一个不带泛型的对象赋给一个带泛型的变量,就会发生“堆污染”。
@SafeVarargs:专门用于去掉堆污染的警告,可见:@SafeVarargs与@SuppressWarnings的作用大致类似,@SuppressWarnings可以压制编译器警告,SafeVarargs只压制堆污染警告。
堆污染:将带泛型的数组元素赋值给不带泛型的数组元素,将如List[] a = newList[5]
a[0] = new List(); 用来修饰私有实例方法。
建议:当用该注解去掉警告时,一定要先认真检查源代码,确保程序没问题才谨慎使用
5、@FunctionalInterface:要求被修饰的接口必须是函数式接口(只有一个抽象方法,可以包含其他多个私有方法、默认方法等),否则报错。
JDK在java.lang.annotation包下的几个meta(元)注解:
元注解:它们也是JDK内置的,这些注解主要用于修饰其他注解。
当希望定义自己的注解时,程序就用元注解来修饰这写注解。
1、@Retention:只能修饰注解定义,用于指定被修饰的注解可以保留到什么时候,它的value属性会支持如下3个枚举值:
-1、RetentionPolicy.SOURCE:被修饰的注解只能保留在源代码中,被javac编译之后,在class文件中该注解就被丢弃。如果使用这种保留策略的注解,这种注解必须在javac编译时处理。
-2、RetentionPolicy.CLASS:被修饰的注解只能保留在class代码中,被javac编译之后,注解还存在,但程序运行时,这种保留策略的注解也是读不到的——这个是默认值。
如果使用这种保留策略的注解,要么在javac编译时处理,要么直接去class文件中读取。
-3、RetentionPolicy.RUNTIME:被修饰的注解将一直被保留(保留到程序运行时)
如果使用这种保留策略的注解,该注解可以在任意时间处理。
RUNTIME策略 > CLASS策略 > SOURCE策略
用法:@Retention(RetentionPolicy.RUNTIME)//定义下面的注解Testable保留到运行时
Public @interface Testable{}
因为@Retention的变量名为value,当注解成员变量为value时,程序可以直接在注解后的括号里指定该成员变量的值,无需使用name =value的形式。
若希望通过反射获取注解信息,就需要使用value属性为RetentionPolicy.RUNTIME的@Retention注解
2、@Target:只能修饰注解定义,用于指定被修饰的注解只能用于修饰什么程序单元。默认情况下,自定义注解可修饰各种程序单元(比如类、方法、成员变量等),@Target可以限制被修饰的注解只能用于修饰哪种程序单元,value值可以是以下参数:
ElementType.ANNOTATION_TYPE:指定该策略的注解只能修饰注解
ElementType.CONSTRUCTOR:指定该策略的注解只能修饰构造器
ElementType.FIELD:指定该策略的注解只能修饰成员变量
ElementType.LOCAL_VARIABLE:指定该策略的注解只能修饰局部变量
ElementType.METHOD:指定该策略的注解只能修饰方法定义
ElementType.PACKAGE:指定该策略的注解只能修饰包定义
ElementType.PARAMETER:指定该策略的注解只能修饰方法的形参参数
ElementType.TYPE:指定该策略的注解可以修饰类、接口(包括注解类型)或枚举定义。
3、Documented:用于指定被修饰的注解将会被javadoc工具提取到文档中。
有@Documented修饰的注解,使用时将会被提取到API文档中。
无@Documented修饰的注解,使用时不会被提取到API文档中。
4、@Inherited:用于指定被修饰的注解将会自动具有继承性,
假如用@Inherit修饰注解@A,@A修饰了类B,那么类B的子类自动具有@A注解。

自定义注解:
各元注解
语法: 修饰符 @interface 注解名
{
//只能定义成员变量——语法很像定义抽象方法,比类定义变量多一个圆括号。
//default指定默认值,如果不指定,使用时必须要为成员变量指定值
//成员变量的修饰符不管写不写都是默认public,不能是其他修饰符。
变量类型 变量名() [default 值];
}
标记注解:无任何成员变量的注解
该注解没有定义任何的成员变量,因此这意味着该注解不能指定成员变量值(额外信息)——因此,标记注解唯一的作用:根据出现与否来传递信息。如:@Test单元测试 @Override
强调:注解本身并没有作用,要等到注解处理工具去读取注解信息、并根据注解处理信息做进一步处理时才会有作用。
元数据注解:带成员变量的注解
这种注解允许在使用时为成员变量指定值、这样一个注解就可传入多个数据。
【注意】注解的成员变量的修饰符,不管写与不写,总是public
【使用带成员变量的注解时,所有没有默认值的成员变量,都必须在使用时指定值】
如果在使用注解时为成员变量重新指定了值,该新指定的值会覆盖成员变量的默认值。
当注解只需要指定一个成员变量值时(即只有一个成员变量没有默认值或注解本身就只定义了一个没有默认值的成员变量),程序可以省略该成员变量名。
当注解要为多个成员变量指定值时,即使是value成员变量,也要用name=value形式指定。

提取注解信息:
使用注解修饰了类、方法、成员变量等成员之后,这些注解不会自己生效,必须由开发者提供相应的工具来提取并处理注解信息
Java使用java.lang.annotation.Annotation接口来代表程序元素前面的注解,该接口是所有注解的父接口。
java.lang.reflect包下的AnnotatedElement接口代表程序中可以接受注解的程序元素该接口主要有如下几个实现类:
Class:类定义
Constructor:构造器定义
Field:类的成员变量定义
Method:类的方法定义
Package:类的包定义
java.lang.reflect包下包含了一些实现反射功能的工具类,Java 5后java.lang.reflect包提供的反射API增加了读取运行时注解的能力。只有当定义注解时使用了@Retention(RetentionPolicy.RUNTIME)修饰,该注解才会在运行时课件,JVM才会在装在.class文件时读取保存在class文件中的注解信息。
运行时读取注解:

Java中所有可以被注解修饰的程序单元(Class、Method、Constructor、Field)都实现了AnnotatedElement接口,AnnotatedElement代表所有可接受注解的程序单元。所以程序通过反射获取了某个类的AnnotatedElement对象(如Class、Method、Constructor)之后,就可以调用该对象的如下方法访问注解:
AnnotatedElement接口提供了如下常用的方法:
Boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判断该元素程序上是否存在指定类型的注解,如果存在返回true,否则返回false
A getAnnotation(Class annotationClass):获取该程序单元上指定类型的某个注解,如果注解不存在,返回null
A getDeclaredAnnotation(Class annotationClass):获取该程序单元上直接修饰该程序元素、指定类型的注解,获取不到重复注解,多个重复注解修饰时,只能获取到一个,如果注解不存在,返回null
Annotation[] getAnnotations():获取该程序单元上存在的所有注解
Annotation[] getDeclaredAnnotations():获取直接修饰该程序单元上存在的所有注解
A[] getAnnotationsByType(Class annotationClass):功能和getDeclaredAnnotation差不多,获取该程序单元上指定类型的所有注解。主要是针对java8新增的重复注解,可以获取到多个重复的注解,而getDeclaredAnnotation获取不到
A[] getDeclaredAnnotationsByType(Class annotationClass):获取直接修饰该程序单元上指定类型的所有注解。主要是针对java8新增的重复注解,

注解修饰后并不会起任何作用,因此如果希望自定义注解起作用,可以定义一个注解运行时处理工具,注解运行时处理工具的大概内容:
1、通过反射获取到类的方法 Class.forName(类).getMethods()
2、通过Method的方法isAnnotationPresent(注解类)方法判断该方法是否有指定注解
3、如果有注解修饰,可以通过Method的getAnnotation方法获取注解,得到注解信息,或在执行方法时做某些处理。

Java 8对注解的改进:
重复注解:@Repeatable(容器注解的class)
默认情况下,java不允许重复使用同一个注解来修饰相同的程序单元。
在java 8以前,如果需要为同一个程序单元使用相同的注解,程序就需要额外的定义一个容器注解!容器注解——其作用是专门用于容纳多个相同的注解。容器注解通常只有一个value属性,该属性的值可以是一个数组,用于放多个重复的注解。
不使用重复注解时,需要使用一个“容器注解”来组合多个重复的注解。
如:@Results({@Result(name=value),@Result(name=value),@Result(name=value)})
使用重复注解的时候,可以直接放多个相同的注解在目标程序单元前面。但需要对原来的注解进行改造。改造后直接可以单独使用多个@Result
【注意】:容器注解的保留期,必须比被包含的注解的保留期更加长!
【本质】:是否使用重复注解,其本质是完全一样。唯一的区别是:用了重复注解之后,代码更加简洁。
不用重复注解,程序需要使用容器注解来组合多个相同的注解,然后将容器注解放在被修饰的程序单元之前。
容器注解代码:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FkTag {

}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FkTags{

FkTag[] value();

}
如上FkTags类就是一个容器注解,将FkTag 定义为一个类型为FkTag []数组的成员变量,变量名为value(即使用的时候可以省略变量名),使用如下:
@FkTags(@Target,@Target,@Target)
注意:容器注解的保留期必须比它所包含的注解的保留期更长,否则将注解放入容器后,若JVM丢失了容器注解,则里面的注解也会丢弃,编译报错。

使用重复注解,程序直接将多个相同的注解放在被修饰的程序单元之前。使用重复注解,只要使用@Repeatable注解修饰容器注解即可,如下:
@Repeatable(FkTags.class)
此时,当直接把多个相同的注解放在目标程序单元之前,java的本质依然会将多个相同的注解组合成容器注解。
【处理注解时的区别】:程序直接使用重复注解时,程序可以通过反射获取到重复注解,如果先使用容器注解包装多个相同的注解,程序使用反射时将获取不到重复注解,只能获取到容器注解。

类型注解:
Java8为ElementType增加了如下两个枚举值:
TYPE_PARAMETER:这种策略的注解,只能修饰泛型声明形参,普通参数声明是不行的
ElementType.PARAMETAR:这种策略的注解,只能用于修饰方法的形参。
ElementType.TYPE_PARAMETER:这种策略的注解,只能用于修饰泛型的形参(包括类型 中、方法中的泛型形参)。

TYPE_USE:这种策略的注解,将可用于修饰所有使用类型(声明变量、继承父类、实现接口、形参、创建对象、throws抛出异常…)的地方——只用用到某个类型,就可使用该策略的注解修饰类型
【注意】默认没有开启该类型注解

Java 9 为ElementType增加了一个MOUDLE枚举值,该枚举值代表被修饰的注解只能修饰模块。

处理注解——让注解发挥作用
APT(Annotation Processing Tool)是一种注解处理工具,它会对源代码进行检测,并找出源文件所包含的注解信息,然后针对注解信息进行额外的处理。
使用APT可以代替传统的Udine代码信息和附属文件的维护工作。
注解:是添加到java源程序中的额外信息,它本身并不会起任何作用。
只有等到使用注解处理工具去解析它时才会起实际的作用。
根据@Retention注解的作用,它指明了目标注解可保留到以下三个阶段:

  • SOURCE:注解只保留在源代码中,javac一旦编译源程序,生成class文件就会丢失这些注解信息。
    -CLASS:注解会保留到class文件,程序可读取class文件中注解信息。
    -RUNTIME:注解一直会保留到运行时,程序可在运行时去读取注解信息。
    处理注解的时机:
    A、编译时提取注解信息,并根据注解信息做进一步的处理,为javac命令指定-processor选项来指定自己的注解处理工具(APT)类。编译时处理工具类必须实现Proceessor接口,该接口有多个方法需要实现,因此,一般通过继承AbstractProcessor类来实现注解处理器。
    实现步骤:
    1、实现Proceessor接口,通过继承AbstractProcessor类来实现注解处理器
    2、在APT类前用注解@SupportedSourceVersion()指定使用Java版本 @SupportedAnnotationTypes注解指定处理哪些注解,属性value是一个数组
    3、类体通过RoundEnvironment类的getElmentsAnnotatedWith()方法获取需要处理的程序单元,最后获取到注解类、成员变量等信息。

B、在运行时程序以反射来提取程序中的注解信息(@Retention是RUNTIME保留期)
实现步骤
1、通过反射获取到类的方法 Class.forName(类).getMethods()
2、通过Method的方法isAnnotationPresent(注解类)方法判断该方法是否有指定注解
3、如果有注解修饰,可以通过Method的getAnnotation方法获取注解,得到注解信息, 或在执行方法时做某些处理。

例子1:为一个测试类,增加一个@Test注解之后,这写方法就会被自动执行。
例子2:使用注解为按钮添加事件监听器
注解总结:注解本身很简单,很容易定义注解,也很容易使用注解。
定义注解:@interface定义程序单元,注解可定义属性。
使用注解:把注解放在任何合适的程序单元之前
注解本身病不会起任何的作用,它只是添加在java程序上的一些额外信息。
必须使用注解处理工具去提取注解信息、根据这些信息做额外的处理,此时注解才会生效,因此,注解通常用于代替原有的XML配置,用于提供配置信息。

编程,用于处理数据。
文件IO:将数据保存到文件等其他物理设备上,保存数据可以在程序之后持久保存。
File类:
代表文件或目录。只能(创建、删除、重命名)操作文件或目录本身。不能读取文件的内容。
File的基本用法:
1、创建File对象(调用构造器将目录或文件包装成对象)
2、调用方法——不同方法需要参考API文档
调用方法时,要啥参数就传递啥参数。
常用方法:
Static listRoots():列出磁盘的所有根路径(盘符)。
String[] list():列出当前目录下的所有文件和子目录

小例子:递归来遍历所有文件
从某个目录开始,依次把所有文件都访问一遍。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值