正如我一直理解的那样,instanceof
合适的主要案例是:
Object.equals(Object)
。因此,如果我正在撰写List
课程,而不是出于任何原因而延伸AbstractList
,我会首先测试equals(o)
,然后比较元素来实施o instanceof List
。Collections.binarySearch
执行instanceof RandomAccess
测试,并对RandomAccess
和非RandomAccess
列表使用稍有不同的二进制搜索。我不认为instanceof
代表这两种情况下的代码气味。但是有没有其他情况下使用instanceof
是明智的吗?
答案 0 :(得分:6)
您控制范围之外的旧版代码或API是instanceof
的合法用例。 (即便如此,我宁愿在它上面写一个OO层,但时间有时会排除这样的重新设计。)
特别是,基于外部类层次结构的工厂似乎是常见用法。
答案 1 :(得分:6)
回答问题的一种方法是回答“实体Java库何时使用instanceof
?”如果我们假设Guava是一个设计良好的Java库的示例,我们可以查看它使用instanceof
的位置来决定何时可以接受。
如果我们提取Guava源代码jar并grep它,我们会看到instanceof
在122个文件中被提及439次:
$ pwd
/tmp/guava-13.0.1-sources
$ grep -R 'instanceof' | wc -l
439
$ grep -Rl 'instanceof' | wc -l
122
在查看其中一些案例时,我们可以看到几种模式出现:
检查是否相等
这是最常见的用法。这在某种程度上是特定于实现的,但假设您确实希望基于它扩展/实现的类/接口来测量相等性,您可以使用instanceof
来确保您正在使用的对象。但是,如果子类覆盖equals()
并且不尊重与父级相同的instanceof
要求,则可能会导致奇怪的问题。各处都有例子,但Lists.equalsImpl()
使用的是ImmutableList
。{/ p>
短路不必要的对象构建
您可以使用instanceof
检查传入的参数是否可以安全使用或返回而无需进一步转换它,例如,如果它已经是所需类的实例,或者我们知道它是不可变的。请参阅CharMatcher.forPredicate()
,Suppliers.memoize()
,ImmutableList.copyOf()
等中的示例。
访问实施细节,而不会暴露不同的行为
这可以在Guava的所有地方看到,但特别是在com.google.common.collect
包中的静态实用程序类中,例如在Iterables.size()
中,如果可能的话,它会调用Collection.size()
,并且否则在O(n)
时间内计算迭代器中的项目数。
避免致电toString()
我怀疑这个优点是在非常少的情况下完成的,但假设你确定你做的是正确的事情,你可以避免不必要地将CharSequence
个对象转换为{{1} String
与instanceof
相同。
执行复杂的异常处理
显然,“正确”的事情是使用Joiner.toString(Object)
块(尽管真的,那已经在进行try/catch
检查),但有时你有更复杂的处理逻辑,值得使用条件块或传递处理单独的方法,例如拉出原因或具有特定于实现的处理。可以在instanceof
。
有一点可以看出这种行为,几乎所有这些都在解决问题我不应该解决。它们在库代码中很有用,例如在SimpleTimeLimiter.throwCause()
,但如果我正在实现这种行为,我应该问自己是否没有库或实用程序可以解决这个问题。
在所有情况下,我都会说Iterables
检查只能在内部用作实现细节 - 也就是说任何依赖于instanceof
检查的方法的调用者都不应该能够(轻松地)告诉你这是做了什么。例如,instanceof
始终返回ImmutableList.copyOf()
。作为一个实现细节,它使用ImmutableList
来避免构造新的instanceof
,但这不是可接受地提供预期行为的必要条件。
顺便说一下,当我在挖掘Guava的源代码时,看到你的名字路易斯很有趣。我发誓我不知道!
答案 2 :(得分:4)
您的第一个案例是我不使用instanceof
运算符的示例,但请查看类是否相等:
o != null && o.getClass() == this.getClass()
这样可以避免将A extends B
和B
的实例视为相等
我可以立即想到其他情况,但我非常确定有更多有效案例可供使用
canCreate
和create
方法,它接收一般接口作为参数。每个工厂都可以处理接口的特定实现,因此需要instanceof
。仅定义工厂抽象类/接口中的接口允许例如编写复合工厂答案 3 :(得分:-1)
正如您所提到的,instanceof
的“正确”用法相当有限。据我所知,你基本上总结了两个主要用途。
但是,您可以稍微概括一下您的陈述,但如下所示: