(请不要建议我更抽象X
并添加另一种方法。)
在C++中,如果我有一个类型为X*
的变量x
,并且我希望在它也是Y*
类型(其中Y
是X
的子类)时执行特定操作,我会写下这个:
if(Y* y = dynamic_cast<Y*>(x)) {
// now do sth with y
}
在Java中似乎不可能做到这一点(或者可以吗?)。
我阅读了这段Java代码:
if(x instanceof Y) {
Y y = (Y) x;
// ...
}
有时,当你没有一个变量
x
,而是一个更复杂的表达式时,在Java中由于这个问题,你需要一个虚拟变量:X x = something();
if(x instanceof Y) {
Y y = (Y) x;
// ...
}
// x not needed here anymore
通常情况下,something()
是 iterator.next()
。你也可以看到,你真的不能仅仅调用它两次。你确实需要一个虚拟变量。
在这里,你实际上根本不需要 x
- 你只是有它,因为你无法一次性进行强制转换的 instanceof
检查。再次将其与相当普遍的 C++ 代码进行比较:
if(Y* y = dynamic_cast<Y*>( something() )) {
// ...
}
因此,我引入了一个
castOrNull
函数,可以避免使用虚拟变量x
。现在我可以这样写:Y y = castOrNull( something(), Y.class );
if(y != null) {
// ...
}
castOrNull
的实现:
public static <T> T castOrNull(Object obj, Class<T> clazz) {
try {
return clazz.cast(obj);
} catch (ClassCastException exc) {
return null;
}
}
现在,有人告诉我以那种方式使用
castOrNull
函数是一件邪恶的事情。为什么?(或者更普遍地提问:你是否同意并认为这是邪恶的?如果是,为什么?或者你认为这是一个有效的(也许是罕见的)用例?)
如上所述,我不想讨论使用这种向下转型是否是一个好主意。但让我简要澄清一下为什么有时候我会使用它:
有时候我会遇到这样的情况:我必须在添加一个非常特定的新方法(仅适用于一个单独的子类和一个特定的案例)之间做出选择,或者使用这样的
instanceof
检查。基本上,我可以选择添加一个函数doSomethingVeryVerySpecificIfIAmY()
或者进行instanceof
检查。在这种情况下,我觉得后者更加清晰。有时候我有一组某个接口/基类的对象,对于所有类型为
Y
的条目,我想做一些操作,然后将它们从集合中移除。(例如,我曾经遇到过这样的情况:我有一个树形结构,我想删除所有的空叶子节点。)