Alb*_*ert 6 java dynamic-cast casting instanceof
(请不要告诉我应该抽象X更多并添加另一种方法.)
在C++中,当我有一个x类型的变量,X*并且我想要做一些特定的事情,如果它也是类型Y*(Y作为其子类X),我写这个:
if(Y* y = dynamic_cast<Y*>(x)) {
// now do sth with y
}
Run Code Online (Sandbox Code Playgroud)
在Java中似乎不可能做同样的事情(或者是吗?).
我已经阅读了这个Java代码:
if(x instanceof Y) {
Y y = (Y) x;
// ...
}
Run Code Online (Sandbox Code Playgroud)
有时,当你没有变量x但是它是一个更复杂的表达式时,正是因为这个问题,你需要在Java中使用一个虚拟变量:
X x = something();
if(x instanceof Y) {
Y y = (Y) x;
// ...
}
// x not needed here anymore
Run Code Online (Sandbox Code Playgroud)
(常见的是,something()是iterator.next().还有你看,你也不能真正称之为两次即可.你真的需要虚拟变量.)
x在这里你根本不需要- 你只是拥有它,因为你不能instanceof立即用演员表进行检查.再次将它与相当常见的C++代码进行比较:
if(Y* y = dynamic_cast<Y*>( something() )) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
因此,我引入了一个castOrNull可以避免虚拟变量的函数x.我现在可以写这个:
Y y = castOrNull( something(), Y.class );
if(y != null) {
// ...
}
Run Code Online (Sandbox Code Playgroud)
执行castOrNull:
public static <T> T castOrNull(Object obj, Class<T> clazz) {
try {
return clazz.cast(obj);
} catch (ClassCastException exc) {
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我被告知以这种castOrNull方式使用这个功能是一件坏事.这是为什么?(或者提出更一般的问题:你是否同意并认为这是邪恶的?如果是,为什么会这样?或者你认为这是一个有效的(可能是罕见的)用例?)
如上所述,我不想讨论是否使用这种垂头丧气是一个好主意.但是,让我稍后澄清为什么我有时会使用它:
有时我会遇到这样的情况:我必须在为特定事物添加另一个新方法(在一个特定情况下仅适用于一个子类)或使用此类instanceof检查之间进行选择.基本上,我可以选择添加功能doSomethingVeryVerySpecificIfIAmY()或进行instanceof检查.在这种情况下,我觉得后者更干净.
有时我有一些接口/基类的集合,对于所有类型的条目Y,我想做一些事情,然后从集合中删除它们.(例如,我遇到了一个树结构的情况,我想删除所有空叶子.)
Ser*_*min 19
从 Java 14 开始,您应该能够instanceof同时执行和转换。请参阅https://openjdk.java.net/jeps/305。
代码示例:
if (obj instanceof String s) {
// can use s here
} else {
// can't use s here
}
Run Code Online (Sandbox Code Playgroud)
上例中的变量 s 在instanceof计算结果为 true 时被定义。变量的范围取决于上下文。请参阅上面的链接以获取更多示例。
现在,我被告知以这种方式使用这个castOrNull函数是一件坏事.这是为什么?
我可以想到几个原因:
做一些非常简单的事情是一种模糊而棘手的方式.模糊和棘手的代码难以阅读,难以维护,潜在的错误来源(当有人不理解时),因此也是邪恶的.
castOrNullJIT编译器无法优化该方法最常用的模糊和棘手的方法.你最终会得到至少3个额外的方法调用,以及许多额外的代码来进行类型检查和反射转换.不必要地使用反射是邪恶的.
(相比之下,简单的方法(instanceof后跟一个类强制转换)使用特定的字节码进行instanceof和类型转换.字节码序列几乎可以肯定会被优化,因此只有一个空检查,并且不再有一个测试本机代码中对象的类型.这是一种常见的模式,JIT编译器应该很容易检测和优化.)
当然,"邪恶"只是另一种说法,你真的不应该这样做.
您添加的两个示例都没有使用castOrNull必要或可取的方法.IMO,从可读性和性能角度来看,"简单方法"更好.
在大多数编写良好/设计的Java代码中,使用instanceof和强制转换都不会发生.随着泛型的增加,不需要许多情况下的演员表(因此也不需要).它们确实偶尔会发生.
castOrNull方法是邪恶的,因为你使Java代码看起来"不自然".从一种语言转换到另一种语言时最大的问题是采用新语言的惯例.临时变量在Java中很好用.实际上你所做的所有方法都是隐藏临时变量.
如果你发现你正在编写很多演员表,你应该检查你的代码并查看原因,并寻找删除它们的方法.例如,在你提到添加"getNumberOfChildren"方法的情况下,你可以检查节点是否为空,从而能够在不进行转换的情况下修剪它(这是猜测,在这种情况下它可能不适合你).
一般来说,演员阵容在Java中是"邪恶的",因为它们通常是不需要的.你的方法更"邪恶",因为它不是以大多数人期望编写Java的方式编写的.
话虽这么说,如果你想这样做,那就去吧.它实际上并不是"邪恶的",只是不是"正确"的方式在Java中这样做.
| 归档时间: |
|
| 查看次数: |
9737 次 |
| 最近记录: |