【发布时间】:2010-10-16 14:07:37
【问题描述】:
(请不要建议我应该抽象 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;
}
}
现在,有人告诉我using this castOrNull function in that way is an evil thing do to。这是为什么? (或者更笼统地说:你会同意并认为这是邪恶的吗?如果是,为什么会这样?或者你认为这是一个有效的(可能是罕见的)用例吗?)
如前所述,我不想讨论使用这种向下转换是否是一个好主意。但让我简要说明一下为什么我有时会使用它:
-
1234563基本上,我可以选择添加函数
有时我有一些接口/基类的集合,对于
Y类型的所有条目,我想做一些事情,然后将它们从集合中删除。 (例如,我有一个树结构,我想删除所有空叶子的子节点。)
doSomethingVeryVerySpecificIfIAmY() 或执行instanceof 检查。而且在这种情况下,我觉得后者更干净。
【问题讨论】:
-
我会使用 instanceOf 而不是 class.cast 以避免在 castOrNull 中出现不必要的异常,但除此之外你似乎有完全正常的帮手。让 Tom 澄清他的意思。
-
如果 Y 是 X 的 超类,则根本不需要强制转换 - 您的意思是 subclass 吗?
-
虽然这不是 Java 中的单行代码,但 instanceof 和强制转换的性能相当不错。我在 Java7 中围绕解决问题的不同方法发布了一些时间:stackoverflow.com/questions/16320014/…
-
您的两个示例似乎都违反了对子类的“是”测试。例如,为什么您的节点没有“deleteEmptyChildren”方法?我的猜测是因为你将它与其他一些类结合起来,它实际上应该“具有”指向另一个类的指针。一般来说,我认为你只是过度使用继承。请记住始终更喜欢封装而不是继承。
标签: java casting instanceof dynamic-cast