替换为Java的instanceof?


10

因此,我对现实世界中的编程(学术项目之外)还很陌生,并且遇到了很多帖子,他们说instanceof使用来确定特定对象的类是一件坏事。

我的情况是我有三个类,一个基本产品类,一个扩展了该类,另一个扩展了该类。这些都存储在数据库的同一表中,我有一些代码需要使用每个方法来提取数据。

解决这种问题的最佳实践是什么?我已经阅读了有关多态性的一些知识,但是找不到解决我所遇到问题的任何示例。它们通常都覆盖了一个对我来说不起作用的方法,因为我需要从不同的对象中提取不同的东西。

有没有更好的方法可以做到这一点,还是我坚持使用instanceof某种反射来获取特定于对象的字段?


10
并不是说关键字instanceof是错误的;试图找到对象的类通常是问题所在。并非总是错误的,但是可能是您的情况。也许如果您告诉我们您要完成的工作,我们可以建议使用多态的解决方案。
Andres F.

2
好的,每个类都有特定于它的数据。我想从中提取特定数据。我想我已经得到了帮助,已经意识到了答案。诸如方法之类的方法getSpecifics()在每个方法上实现不同,每个方法返回特定于该类的数据?
Thomas Mitchell

Answers:


16

instanceof沮丧的原因是它不是面向对象的。

对象的调用者/用户应该没有理由知道它是实例的哪个具体类,而不是其声明为哪种类型的实例。

如果在子类中需要不同的行为,则添加一个方法并以不同的方式实现它们。


1
因此getSpecifics(),每个类上的方法(或类似方法)将返回每个类的详细信息。这是最好的方法吗?
Thomas Mitchell

@Schmooo您确实需要考虑一下通用功能在类树中的位置以及每个级别上的合同。

3
但是,当您的对象跨层并且类型信息丢失时,情况又如何呢?我创建一个示例List。我将其传递给任何对象Iterable。现在,第二个对象将其传递给第三个对象,该对象要么List进行优化,要么进行优化,Iterable但速度要慢得多。第二个不应该知道它的列表,但是第三个非常想知道。第三个对象是否不应该检查instanceof以确定是否可以应用优化?例如,番石榴FluentIterable就是这样做的。
Laurent Bourgault-Roy

1
我要说的是,并非总是必须将方法添加到类中。例如,某些代码会获得异常,并应根据其类型对异常进行处理。说,做出报告或做一些事情来从错误中恢复。这种功能肯定不适合例外情况。或者,如果这些类来自某个外部库,那么您甚至没有办法修改这些类。在这种情况下,我认为依靠绝对是正确的instanceof
马尔科姆

9

instanceof 不一定是一件坏事,但这是一个应该注意的事情。

一个可以正常工作的示例是在一个地方获得基本类型的集合,而您只想要一个子类型的地方。从中获取网络地址会NetworkInterface.getNetworkInterfaces()返回NetworkInterface对象,该对象具有InetAddress对象的集合,其中一些是Inet4Address,一些是Inet6Address。如果要过滤Inet4Address对象的集合,则必须使用instanceof。

在原始帖子中描述的情况下,有一个基类,它扩展了该基类,又扩展了该扩展类。尽管信息不完全,但这似乎是一些不理想的设计的基础。

当您返回基类时,除非有充分的理由以这种方式设计基类(早期版本的规范之间向后兼容),否则您不应尝试窥视基础类型。如果返回了Set,则知道您正在获取Set。它允许开发人员以后改变主意,以返回更特定的类型(SortedSet)或更改基础类型(从HashSet到TreeSet),而不会破坏任何内容。

重新考虑对象的结构和父级设计,以查看是否可以创建不需要区分类型的更好的类模型。


isOfType(SomeEnum.IPv4)与通过检查具体类型相比,让接口指定方法可能是一种更好的过滤此类质量的方法instanceof。如果要稍后拆分IPv4实现类怎么办?并不是说总会更好,但这是一个考虑因素。
Steven Schlansker

@StevenSchlansker可以为该特定班级工作。但是,如果需要检查具体类型以查看是否可以进行强制转换(或者只是强制转换并捕获异常),该怎么办?Inet6Address比InetAddress实现的方法更多。它很难与接口一起工作(枚举枚举包中的每个类?还是类加载器?),这意味着该方法将需要手动实现(或对象中的一些反射代码)。考虑该怎么做(o instanceof Serializable) || (o instanceof Externalizable)。instanceof比替代方法更好

1

您可以使用getClass()方法。

您确定需要三种不同的课程吗?也许一个内部有开关的班级会更好?


7
getClassinstanceof分享缺点。当适合时,多态性要好于两者,而且我不认为它不适合OP的用例。

我没有反对你的第一句话。但是第二个-对不起,我根本不明白你的意思。
Gangnus

1
getClass,我仍然不会遇到与使用相同的问题instanceof?我仍然必须找出我所拥有的,然后调用一组函数。理想情况下,我需要一个方法,该方法可以返回特定于该类的数据,而无需强制转换为该对象。
Thomas Mitchell 2013年

我抱怨您忽略了多态性,因为它通常是一个更好的选择。我很确定问题中的用例可以通过多态来完成,所以我认为两者都不需要使用。(除此之外,仅复制其他人的答案是不好的。)

2
@angus我不认为这是“攻击”,我的意思是没有冒犯。但是无所谓。不,问题不是“还有什么可以使用的”,而是“是否有更好的方法可以使用”。除非您想证明getClass这样做是一种更好的方法,否则它不会解决大部分问题;-)

1

通常,当我发现自己想知道某种事物的类型时,这意味着我错误地实现了对象结构。在大多数情况下,它归结为违反LSP

但是,有时候我希望我有一种方法可以进行动态调度,并节省大量的样板代码和使我的对象结构更可靠的方法。C#在框架的较新版本中提供了dynamic关键字,但据我所知,Java仍然没有类似的东西。

也就是说,instanceof通常比比较类更好,因为它可以正确支持继承。您还可以使用反射API中的isAssignableFrom之类的方法和其他方法。如果要实现诸如动态调度之类的操作,则可以通过反射API来完成,但是请注意,这会很慢。谨慎使用,理想情况下,如果可以的话,应该修复应用程序的对象结构和设计。

希望这可以帮助

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.