class A {}
class B extends A {}
public class Benchmark {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(TestPerf2.class.getSimpleName())
.warmupIterations(20)
.measurementIterations(2000)
.forks(1)
.build();
new Runner(opt).run();
}
}
class A{}
class B extends A{}
A b = new B();
boolean execute(){
return A.class.isAssignableFrom(b.getClass());
// return A.class.isInstance(b);
// return b instanceof A;
}
// Warmup the code
for (int i = 0; i < 100; ++i)
execute();
// Time it
int count = 100000;
final long start = System.nanoTime();
for(int i=0; i<count; i++){
execute();
}
final long elapsed = System.nanoTime() - start;
我们在团队中进行的一些测试显示 A.class.isAssignableFrom(B.getClass()) 的工作速度比 B instanceof A 快 . 如果您需要在大量元素上进行检查,这可能非常有用 .
101
在性能方面谈论“2”(与JMH):
class A{}
class B extends A{}
public class InstanceOfTest {
public static final Object a = new A();
public static final Object b = new B();
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testInstanceOf()
{
return b instanceof A;
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testIsInstance()
{
return A.class.isInstance(b);
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public boolean testIsAssignableFrom()
{
return A.class.isAssignableFrom(b.getClass());
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(InstanceOfTest.class.getSimpleName())
.warmupIterations(5)
.measurementIterations(5)
.forks(1)
.build();
new Runner(opt).run();
}
}
读 instanceof 为“这是(左侧部分)这个或其任何子类(右侧部分)的实例”并将 x.getClass().isAssignableFrom(Y.class) 读作“我可以写 X x = new Y() ” . 换句话说,instanceof运算符检查左对象是否是右类的相同或子类,而 isAssignableFrom 检查我们是否可以将参数类(from)的对象分配给调用该方法的类的引用 . 请注意,这两个都认为实际的实例不是引用类型 .
考虑3个类A,B和C的示例,其中C扩展B,B扩展A.
B b = new C();
System.out.println(b instanceof A); //is b (which is actually class C object) instance of A, yes. This will return true.
System.out.println(b instanceof B); // is b (which is actually class C object) instance of B, yes. This will return true.
System.out.println(b instanceof C); // is b (which is actually class C object) instance of C, yes. This will return true. If the first statement would be B b = new B(), this would have been false.
System.out.println(b.getClass().isAssignableFrom(A.class));//Can I write C c = new A(), no. So this is false.
System.out.println(b.getClass().isAssignableFrom(B.class)); //Can I write C c = new B(), no. So this is false.
System.out.println(b.getClass().isAssignableFrom(C.class)); //Can I write C c = new C(), Yes. So this is true.
13 回答
instanceof
只能与引用类型一起使用,而不能与基本类型一起使用 .isAssignableFrom()
可以与任何类对象一起使用:见http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
在性能方面谈论:
TL;DR
使用具有相似性能的 isInstance 或 instanceof . isAssignableFrom 稍慢 .
按性能排序:
isInstance
instanceof (0.5%)
isAssignableFrom (2.7%)
基于JAVA 8 Windows x64上2000次迭代的基准测试,具有20次预热迭代 .
In theory
使用类似bytecode viewer的软件,我们可以将每个运算符转换为字节码 .
在以下情况下:
JAVA:
字节码:
JAVA:
字节码:
JAVA:
字节码:
测量每个运算符使用多少字节码指令,我们可以预期 instanceof 和 isInstance 比 isAssignableFrom 更快 . 但是,实际性能不是由字节码决定的,而是由机器代码决定的(取决于平台) . 让我们为每个运营商做一个微基准测试 .
The benchmark
信用:正如@ aleksandr-dubinsky所建议的那样,并且感谢@yura提供基本代码,这里有一个JMH基准(请参阅tuning guide):
给出以下结果(得分是一个时间单位的操作数,所以得分越高越好):
Warning
该基准测试依赖于JVM和平台 . 由于每个操作之间没有显着差异,因此可能在不同的JAVA版本和/或Solaris,Mac或Linux等平台上获得不同的结果(可能是不同的顺序!) .
基准比较直接"B extends A"时"is B an instance of A"的性能 . 如果类层次结构更深且更复杂(如B扩展X扩展Y,扩展Z扩展A),结果可能不同 .
通常建议首先选择一个运算符(最方便)编写代码,然后分析代码以检查是否存在性能瓶颈 . 也许这个运算符在代码的上下文中可以忽略不计,或者......
与上一点相关的
,代码上下文中的
instanceof
可能比isInstance
更容易优化,例如......举个例子,采取以下循环:
感谢JIT,代码在某些时候进行了优化,我们得到:
instanceof:6ms
isInstance:12ms
isAssignableFrom:15ms
Note
最初这篇文章是在原始JAVA中使用for循环进行自己的基准测试,由于像Just In Time这样的优化可以消除循环,因此产生了不可靠的结果 . 因此,它主要测量JIT编译器优化循环所需的时间:有关详细信息,请参阅Performance test independent of the number of iterations
Related questions
Does instanceof operator generate a lot of overhead ? Why?
How instanceof is implemented inside JAVA?
The performance impact of using instanceof in Java
考虑以下情况 . 假设你要检查类型A是否是obj类型的超类,你可以去
... A.class.isAssignableFrom(obj.getClass())...
要么
... obj instanceof A ...
但isAssignableFrom解决方案要求obj的类型在这里可见 . 如果不是这种情况(例如,obj的类型可能是私有内部类),则该选项不存在 . 但是,解决方案的实例始终有效 .
还有另一个不同之处 . 如果要测试的类型(Class)是动态的,例如作为方法参数传递,然后instanceof不会为你剪切它 .
但你可以这样做:
哎呀,我看到这个答案已经涵盖了 . 也许这个例子对某人有帮助 .
还有另一个不同之处:
无论X是什么,null instanceof X都是
false
null.getClass() . isAssignableFrom(X)将抛出NullPointerException
如果类型/类A的引用可以从类型/类B的引用分配,则上面的伪代码是定义 . 它是递归定义 . 对某些人来说,这可能会有所帮助,对于其我添加它以防有人应该发现它有用 . 这只是为了捕捉我的理解,它不是官方的定义 . 它用于某个Java VM实现并适用于许多示例程序,因此虽然我不能保证它捕获了isAssignableFrom的所有方面,但它并没有完全关闭 .
我们在团队中进行的一些测试显示
A.class.isAssignableFrom(B.getClass())
的工作速度比B instanceof A
快 . 如果您需要在大量元素上进行检查,这可能非常有用 .在性能方面谈论“2”(与JMH):
它给:
因此,我们可以得出结论: instanceof 与 isInstance() 一样快, isAssignableFrom() 不远处(0.9%执行时间) . 所以没有真正的区别无论你选择什么
instanceof也不能与基本类型或泛型类型一起使用 . 如下面的代码所示:
错误是:无法对类型参数T执行instanceof检查 . 使用它的擦除对象,因为在运行时将删除其他泛型类型信息 .
由于类型擦除删除运行时引用而无法编译 . 但是,下面的代码将编译:
使用
instanceof
时,需要在编译时知道B
的类 . 使用isAssignableFrom()
时,它可以是动态的,并在运行时更改 .更直接等同于
a instanceof B
当
a
也是null
时,这可以工作(返回false) .除了上面提到的基本差异之外,instanceof运算符和Class中的isAssignableFrom方法之间存在核心细微差别 .
读
instanceof
为“这是(左侧部分)这个或其任何子类(右侧部分)的实例”并将x.getClass().isAssignableFrom(Y.class)
读作“我可以写X x = new Y()
” . 换句话说,instanceof运算符检查左对象是否是右类的相同或子类,而isAssignableFrom
检查我们是否可以将参数类(from)的对象分配给调用该方法的类的引用 .请注意,这两个都认为实际的实例不是引用类型 .
考虑3个类A,B和C的示例,其中C扩展B,B扩展A.
这个帖子让我对
instanceof
与isAssignableFrom
的不同有所了解,所以我想我会分享一些属于自己的东西 .我发现使用
isAssignableFrom
是唯一的(可能不是唯一的,但可能是最简单的)方式来询问一个人的自我,如果一个类的引用可以接受另一个类的实例,当一个类没有类的实例进行比较时 .因此,我没有发现使用
instanceof
运算符来比较可赋值性是一个好主意,当我所有的都是类时,除非我考虑从其中一个类创建一个实例;我以为这会马虎 .