dso*_*len 14 java optimization casting instanceof
在任何人说什么之前我只是出于好奇而问这个问题; 我不打算根据这个答案做任何过早的优化.
我的问题是关于使用反射和铸造的速度.标准的说法是"反思很慢".我的问题是哪个部分确实很慢,为什么; 特别是在比较某事物是否是另一个实例的父母时.
我非常有信心只是将对象的类与另一个Class对象进行比较的速度与任何比较一样快,大概只是直接比较已经存储在Object状态中的单例对象; 但如果一个班级是另一个班级的父母呢?
我通常认为instanceof
它与普通班级检查一样快,但今天我想到了它,似乎有些反思必须在"幕后" instanceof
才能发挥作用.我在网上查了一下,发现有人说的instanceof
很慢; 大概是因为比较物体的父母所需的反射?
这导致了下一个问题,如何只是铸造.如果我把某事物作为一个物体,那我就得不到了ClassCastException
.但是如果将对象转换为自身的父对象,则不会发生这种情况.基本上我正在做一个instanceof
电话,或逻辑到那个效果,当我在运行时进行演员表明我不是吗?我从来没有听到过任何人暗示过投射物体之前可能会很慢.不可否认,并非所有演员都是提供对象的父级,但很多演员都是父类.然而,从来没有人暗示这可能会很慢.
那是哪个呢.是instanceof
真的没有那么慢?两者都instanceof
投射到父类有点慢吗?或者有什么理由可以比instanceof
电话更快地完成演员表?
Ric*_*gle 19
一如既往地尝试并在您的特定情况下看到,但是:
- 例外是昂贵的,非常明显.
- 使用代码流的异常几乎总是一个坏主意
编辑:好的我感兴趣所以我写了一个快速测试系统
public class Test{
public Test(){
B b=new B();
C c=new C();
for(int i=0;i<10000;i++){
testUsingInstanceOf(b);
testUsingInstanceOf(c);
testUsingException(b);
testUsingException(c);
}
}
public static void main(String[] args){
Test test=new Test();
}
public static boolean testUsingInstanceOf(A possiblyB){
if (possiblyB instanceof B){
return true;
}else{
return false;
}
}
public static boolean testUsingException(A possiblyB){
try{
B b=(B)possiblyB;
return true;
}catch(Exception e){
return false;
}
}
private class A{
}
private class B extends A{
}
private class C extends A{
}
}
Run Code Online (Sandbox Code Playgroud)
档案结果:
by InstanceOf: 4.43 ms
by Exception: 79.4 ms
Run Code Online (Sandbox Code Playgroud)
正如我所说,非常昂贵
即使它总是成为B(模拟当你99%确定它的B时你只需要确定它仍然没有更快:
总是B时的档案结果:
by InstanceOf: 4.48 ms
by Exception: 4.51 ms
Run Code Online (Sandbox Code Playgroud)
有一般答案和特定答案.
if (/* guard against exception */) {
/* do something that would throw an exception */
} else {
/* recover */
}
// versus
try {
/* do something that would throw an exception */
} catch (TheException ex) {
/* recover */
}
Run Code Online (Sandbox Code Playgroud)
事实上,创建/抛出/捕获异常是昂贵的.它们可能比进行测试要贵得多.但是,这并不意味着"测试第一"版本总是更快.这是因为在"测试第一"的版本,实际上可能进行的测试:在第一时间if
,并在代码第二次会抛出异常.
当你考虑到这一点时,很明显,如果(额外)测试的成本足够大并且异常的相对频率足够小,"先测试"实际上会更慢.例如,在:
if (file.exists() && file.isReadable()) {
is = new FileInputStream(file);
} else {
System.err.println("missing file");
}
Run Code Online (Sandbox Code Playgroud)
与
try {
is = new FileInputStream(file);
} catch (IOException ex) {
System.err.println("missing file");
}
Run Code Online (Sandbox Code Playgroud)
"测试优先"方法执行2次额外的系统调用,系统调用很昂贵.如果"遗失文件"情况也不寻常......
第二个混淆因素是最新的HotSpot JIT编译器对异常进行了一些重要的优化.特别是,如果JIT编译器可以确定不使用异常对象的状态,它可以将异常create/throw/catch转换为简单的跳转指令.
instanceof
在这种情况下,我们很可能比较这两个:
if (o instanceof Foo) {
Foo f = (Foo) o;
/* ... */
}
// versus
try {
Foo f = (Foo) o;
} catch (ClassCastException ex) {
/* */
}
Run Code Online (Sandbox Code Playgroud)
这里进行第二次优化.A instanceof
后跟a type cast
是一种常见的模式.HotSpot JIT编译器通常可以消除由类型转换执行的动态类型检查...因为这会重复刚刚成功的测试.当你考虑到这一点时,"测试第一"版本不能比"异常"版本慢......即使后者被优化为跳转.