您可以将“@NonNull String”视为 String 的严格子类。毕竟,任何非空字符串肯定是一个 'instanceof' '@Nullable String',但是任何 instanceof '@Nullable String' 都可能不是 '@NonNull String' 的一个实例(如果它是null 就不会,例如)。
这样看,@Nullable 和@NonNull 是类型信息,因此在接口中是完全合理的。您向实现者表明他们可能返回 null,并且他们不必担心输入 null,并且您向调用者表明他们不能传入 null,并且他们应该期待 null 输出。
当然,虽然这一切都非常合理,但 vanilla javac v1.6 肯定不会像强制实际类型的类型安全那样强制执行任何这些规则。但是可以做梦,或者可以使用 pmd 或 findbugs 之类的工具来验证这些注释。
不过,@NonNull 和 @Nullable 注释对于完整的 nullity 类型系统来说是不够的。我真的不知道为什么 JSR305 没有解决这个问题,但是还有第三种类型:“@MaybeNull”。它会出现在泛型参数中;在其他任何地方,它都与@Nullable 具有相同的含义。
public static void addIfNotNull(List<@MaybeNull T> list, @Nullable T item) { if ( item != null ) list.add(item); }
如果第一个“T”上的注释是“@Nullable”,那么您不能传入非空列表,这将导致 API 相当无用。另一方面,如果是@NonNull,则不能传入一个可为空的列表。实际上,无论你在其中移动什么都没关系,它 (A) 永远不会导致 NullPointerException,并且 (B) 永远不会违反注释。所以,你需要一种表达方式:我不在乎这个特定的“T”是否可以为空;当我读取它时,我会进行空值检查,而且我永远不会写空值,所以没关系。
@MaybeNull 和 @Nullable 之间的区别类似于 '? 在泛型中扩展 Number' 和 'Number'。在泛型之外,它们的含义相同,但在泛型中存在差异。
所以,不要对很快的严格类型检查抱有希望。
@Inherited 仅适用于类,但人们会想象带注释的返回类型和带注释的参数有类似的东西。