Guava中的@CompatibleWith注解有什么作用?

3

根据com.google.errorprone.annotations.CompatibleWith的文档:

Declares that a parameter to a method must be "compatible with" one of the type parameters in the method's enclosing class, or on the method itself. "Compatible with" means that there can exist a "reference casting conversion" from one type to the other (JLS 5.5.1).

For example, Collection.contains(java.lang.Object) would be annotated as follows:

interface Collection<E> {
    boolean contains(@CompatibleWith("E") Object o);
}

To indicate that invocations of Collection.contains(java.lang.Object) must be passed an argument whose type is compatible with the generic type argument of the Collection instance:

这里是 com.google.common.cache.Cache 的使用方法:

public interface Cache<K, V> {

    V getIfPresent(@CompatibleWith("K") Object key);

    V get(K key, Callable<? extends V> loader) throws ExecutionException;
...

拥有@CompatibleWith("E") Object作为参数类型相比于E有什么好处?为什么在缓存的getIfPresent方法中使用了@CompatibleWith注解,但在get方法中没有使用?请注意保留HTML标签。
1个回答

2

getIfPresent 操作允许“过于宽泛”的类型的对象是安全的(使用 getIfPresent(42) 的字符串键不会从缓存中获取任何内容)。另一方面,假设的 get(Object, Callable) 允许插入错误类型的对象(例如,将整数42 插入字符串"foo"中),将损坏基础集合,这就是为什么编译时检查不允许它。

话虽如此,以下代码:

Cache<String, Foo> cache = CacheBuilder.newBuilder()
// and later
Foo value = cache.getIfPresent(42);

很可能是错误的,对于像Error Prone这样的框架来标识可能有bug是有意义的。

关于“在安全操作中使用Object而不是泛型类型”的约定(不仅适用于Guava,还适用于JDK集合框架),更详细的解释在这篇旧但仍然相关的博客文章“为什么Set.contains()接受一个Object而不是一个E?”中解释了:

Why should code like the following compile?

Set<Long> set = new HashSet<Long>();
set.add(10L);
if (set.contains(10)) {
  // we won't get here!
}

We're asking if the set contains the Integer ten; it's an "obvious" bug, but the compiler won't catch it because Set.contains() accepts Object. Isn't this stupid and evil?

然后回答了标题中的问题:

真正的区别在于,当使用错误类型调用add()时,它可能会对集合造成“损坏”,而contains()remove()则不会。

结论也很相关:

静态分析在构建无缺陷软件方面起着极其重要的作用。

这是有道理的,因为作者Kevin Bourrillion也是Guava的首席开发人员。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接