1 问题背景
博主最近在深入学习Java注解,其中就了解到注解可用于修饰包声明,因为@Target元注解的value元素数组可以包含ElementType.PACKAGE 元素,接着博主就发现@Deprecated注解就支持修饰包声明:
package java.lang;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
博主直接尝试在包声明或包引入的语句前加上包注解,Java编译器却直接报错了,甚至还导致java.util.List 没有被正确引用:
@Deprecated
package com.example;
@Deprecated
import java.util.List;
public class TestClass {
List list;
}
根据错误提示,我们了解到包注解不能修饰常规Java文件中包声明或包引入语句,而只能用于修饰package-info.java 文件中的包声明语句(也不能修饰package-info.java 文件中的包引入语句)。
那么,我们就自行创建一个package-info.java 文件吧。但是我们需要注意的是,我们不能通过常规的方法来创建一个package-info.java 文件。例如,通过对任意包文件夹鼠标右键再依次选中"New"-“Java”,这种是创建标准的Java类的方式,而Java类名的命名规范中不能有- 符号,因此通过这种方式创建会报错: 我们应当对任意包文件夹鼠标右键再依次选中"New"-"File" 或"New"-"package-info.java" ,这样既可成功创建一个package-info.java 文件: 当我们通过"New"-"File" 的方式创建一个名为package-info.java 的空文件时,IDE会提示咱们这个文件缺少了包声明的语句:
因此我们应该在package-info.java 文件中手动编码当前路径的包声明语句:
package com.exmaple2;
我们通过"New"-"package-info.java" 的方式创建一个package-info.java 文件时,IDE会自动为我们在该文件中编码当前路径的包声明语句,与上述手动编码的包声明语句是完全一致的。
接着我们用@Deprecated注解修饰package-info.java 文件中的包声明语句:
@Deprecated
package com.exmaple2;
我们发现上述代码符合语法规范,并没有报错,IDE甚至贴心地将划线标识com.example 包已经过时了并给予了编译警告:
以上就是包注解的简单用法,即包注解只能用于修饰package-info.java 文件中的包声明语句。
如果你对package-info.java文件的作用和包注解的详细用法特别感兴趣的话,你还可以继续查阅本文后续的内容。
2 package-info.java 文件
package-info.java 文件是一个特殊的Java文件,它里面主要包含3类语句:包注释、包注解和包声明,它可以被放在任意Java包对应的路径下。
下图是安卓开源项目Telegram包含的其中一个package-info.java 文件,你可以看到博主我额外为这个文件加上了包注释:
2.1 package-info.java 文件的作用
其中 package-info.java 文件主要有下述的作用:
2.1.1 提供包级别的注释(Comment)
我们都知道可以为类、变量、方法等元素编写注释,但是如果我们想给某个Java包编写注释怎么办?在Java5之前,需要在Java包对应的路径下创建一个package.html 文件,并在其body标签中编写Javadoc注释。而在Java5及之后的版本中,我们在Java包对应的路径下创建一个package-info.java 文件来存放包的包声明、包注释和包注解:
@NonNullApi
package com.google.android.exoplayer2.analytics;
import com.google.android.exoplayer2.util.NonNullApi;
接着,我们在Telegram项目的目录~/Telegram/TMessagesProj/src/main/java 中执行下述JavaDoc命令来递归生成Telegram项目com 包及其所有子包和子文件的JavaDoc文档:
javadoc -d ../../../../Telegram-JavaDoc -author -version -subpackages com
2.1.2 提供包级别的注解(Annotation)
在Java5及之后的版本中,我们可以在某个Java包对应路径下的package-info.java 文件中用包注解来修饰包声明语句。例如我们想指定某个Spring项目的其中一个Java包中所有类和接口的成员变量都是非空的,就可以用的spring-core库的@NonNullFields注解,例如下述的代码:
@NonNullApi
@NonNullFields
package com.baeldung.nullibility;
import org.springframework.lang.NonNullApi;
import org.springframework.lang.NonNullFields;
但是请注意,上述提到的@NonNullApi 和@NonNullFields 都是Spring 5的spring-core库引入的 jsr-305注解,需要额外添加com.google.code.findbugs:jsr305:3.0.2 依赖项,否则将无法使用这些注解。
《Spring官方文档-空安全》文章中也提到:
没有必要也不推荐将JSR-305依赖项添加到项目中来利用Spring空安全注释。只有像基于Spring的库的项目,即在代码库中使用空安全注释的项目才应该添加com.google.code.findbugs:jsr305:3.0.2 依赖项来避免编译警告。
也就是说,如果我们的项目不是基于Spring的库的项目,例如Android项目就没必要为了这几个空安全注解来引入相关的依赖。Android项目有自己的注解支持库,可以参考《Android官方文档-利用注解改进代码检查》文章。
3 总结
以上就是Java中引入的package-info.java 文件和包注释的作用和用法,如果你的项目中需要包级别的注释的注解,那么你可以考虑在你的项目中使用package-info.java 文件和包注释,否则就不用费心去关注这块的知识点啦。
本文参考文献:
javadoc 命令生成类的解释文档
StackOverFlow-What is package-info.java and how can I add it to my project?
StackOverFlow-Eclipse Juno - What is the use of package-info.java?
StackOverFlow-Why is package-info.java useful?
Java学习系列:package-info.java的作用
PACKAGE-INFO.JAVA 作用及用法详解
Baeldung-The package-info.java File
Annotation attributes with type parameters
How do I add package level annotations or edit package-info.java?
What do Java annotation ElementType constants mean?
Spring Framework Documentation Null-safety
Spring 5 core 中的 @NonNull 是个什么鬼?!
安卓中的@Nullable和NotNull 注释
Android官方文档-利用注解改进代码检查
雷元流-善用注解降低犯错率
简书-javadoc 命令生成类的解释文档
|