以下哪项更好?
a instanceof B
或
B.class.isAssignableFrom(a.getClass())
我所知道的唯一区别是,当'a'为null时,第一个返回false,而第二个抛出异常。除此之外,他们总是给出相同的结果吗?
答案 0 :(得分:465)
使用instanceof
时,您需要在编译时知道B
的类。使用isAssignableFrom()
时,它可以是动态的,并在运行时更改。
答案 1 :(得分:201)
instanceof
只能用于引用类型,而不能用于基本类型。 isAssignableFrom()
可以与任何类对象一起使用:
a instanceof int // syntax error
3 instanceof Foo // syntax error
int.class.isAssignableFrom(int.class) // true
请参阅 http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class)。
答案 2 :(得分:106)
谈论绩效:
<强> TL; DR 强>
使用具有类似效果的 isInstance 或 instanceof 。 isAssignableFrom 略慢。
按表现排序:
基于JAVA 8 Windows x64上2000次迭代的基准测试,有20次预热迭代。
理论上
使用像bytecode viewer这样的软,我们可以将每个运算符转换为字节码。
在上下文中:
package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
JAVA:
b instanceof A;
字节码:
getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
JAVA:
A.class.isInstance(b);
字节码:
ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Class isInstance((Ljava/lang/Object;)Z);
JAVA:
A.class.isAssignableFrom(b.getClass());
字节码:
ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Object getClass(()Ljava/lang/Class;);
invokevirtual java/lang/Class isAssignableFrom((Ljava/lang/Class;)Z);
衡量每个运营商使用的字节码指令数量,我们可以预期 instanceof 和 isInstance 比 isAssignableFrom 更快。但是,实际性能不是由字节码决定的,而是由机器代码决定的(取决于平台)。让我们为每个运营商做一个微基准测试。
基准
信用:正如@ aleksandr-dubinsky所建议的那样,感谢@yura提供基本代码,这里有JMH基准(见tuning guide):
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();
}
}
给出以下结果(得分是时间单位中的一些操作,因此得分越高越好):
Benchmark Mode Cnt Score Error Units
Benchmark.testIsInstance thrpt 2000 373,061 ± 0,115 ops/us
Benchmark.testInstanceOf thrpt 2000 371,047 ± 0,131 ops/us
Benchmark.testIsAssignableFrom thrpt 2000 363,648 ± 0,289 ops/us
警告强>
instanceof
可能比isInstance
更容易优化,例如...... 举个例子,采取以下循环:
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;
感谢JIT,代码在某些时候进行了优化,我们得到了:
注意强>
最初这篇文章在原始JAVA中使用 for 循环进行自己的基准测试,由于Just In Time等一些优化可以消除循环,因此产生了不可靠的结果。因此,它主要测量JIT编译器优化循环所需的时间:有关更多详细信息,请参阅Performance test independent of the number of iterations
相关问题
答案 3 :(得分:33)
更直接等同于a instanceof B
B.class.isInstance(a)
当a
null
为{{1}}时,此方法有效(返回false)。
答案 4 :(得分:22)
除了上面提到的基本差异之外,instanceof运算符和Class中的isAssignableFrom方法之间存在核心细微差别。
将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.
答案 5 :(得分:15)
还有另一个不同之处:
无论X是什么, null instanceof X都是false
null.getClass()。isAssignableFrom(X)将抛出NullPointerException
答案 6 :(得分:11)
还有另一个不同之处。如果要测试的类型(Class)是动态的,例如作为方法参数传递,然后instanceof不会为你剪切它。
boolean test(Class clazz) {
return (this instanceof clazz); // clazz cannot be resolved to a type.
}
但你可以这样做:
boolean test(Class clazz) {
return (clazz.isAssignableFrom(this.getClass())); // okidoki
}
哎呀,我看到这个答案已经涵盖了。也许这个例子对某人有帮助。
答案 7 :(得分:7)
这个帖子让我对instanceof
与isAssignableFrom
的不同之处有所了解,所以我想我会分享一些属于自己的东西。
我发现使用isAssignableFrom
是唯一的(可能不是唯一的,但可能是最简单的)方式来询问自己,如果一个类的引用可以接受另一个类的实例,当一个类具有实例时两个人都没有做比较。
因此,我没有发现使用instanceof
运算符来比较赋值是一个好主意,当我所有的都是类时,除非我考虑从其中一个类创建一个实例;我以为这会马虎。
答案 8 :(得分:4)
考虑以下情况。假设你要检查类型A是否是obj类型的超类,你可以去
... A.class.isAssignableFrom(obj.getClass()) ...
OR
... obj instanceof A. ...
但isAssignableFrom解决方案要求obj的类型在这里可见。如果不是这种情况(例如,obj的类型可能是私有内部类),则该选项不存在。但是,解决方案的实例始终有效。
答案 9 :(得分:3)
instanceof也不能与原始类型或泛型类型一起使用。如下面的代码所示:
//Define Class< T > type ...
Object e = new Object();
if(e instanceof T) {
// Do something.
}
错误是:无法对类型参数T执行instanceof检查。请使用它的擦除对象,因为在运行时将删除其他泛型类型信息。
由于删除运行时引用的类型擦除而无法编译。但是,下面的代码将编译:
if( type.isAssignableFrom(e.getClass())){
// Do something.
}
答案 10 :(得分:0)
isAssignableFrom(A, B) =
if (A == B) return true
else if (B == java.lang.Object) return false
else return isAssignableFrom(A, getSuperClass(B))
如果类型/类A的引用可以从类型/类B的引用分配,则上面的伪代码是一个定义。它是一个递归定义。对某些人来说,这可能会有所帮助,对于其我添加它以防有人应该发现它有用。这只是为了捕捉我的理解,它不是官方的定义。它用于某个Java VM实现并适用于许多示例程序,因此虽然我不能保证它捕获了isAssignableFrom的所有方面,但它并没有完全关闭。
答案 11 :(得分:0)
谈论表现“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();
}
}
它给出了:
Benchmark Mode Cnt Score Error Units
InstanceOfTest.testInstanceOf avgt 5 1,972 ? 0,002 ns/op
InstanceOfTest.testIsAssignableFrom avgt 5 1,991 ? 0,004 ns/op
InstanceOfTest.testIsInstance avgt 5 1,972 ? 0,003 ns/op
这样我们就可以得出结论: instanceof 和 isInstance()以及 isAssignableFrom()一样快(+ 0.9%执行时间) )。无论你选择什么都没有真正的区别
答案 12 :(得分:0)
如何在实际操作中展示一些示例...
@Test
public void isInstanceOf() {
Exception anEx1 = new Exception("ex");
Exception anEx2 = new RuntimeException("ex");
RuntimeException anEx3 = new RuntimeException("ex");
//Base case, handles inheritance
Assert.assertTrue(anEx1 instanceof Exception);
Assert.assertTrue(anEx2 instanceof Exception);
Assert.assertTrue(anEx3 instanceof Exception);
//Other cases
Assert.assertFalse(anEx1 instanceof RuntimeException);
Assert.assertTrue(anEx2 instanceof RuntimeException);
Assert.assertTrue(anEx3 instanceof RuntimeException);
}
@Test
public void isAssignableFrom() {
Exception anEx1 = new Exception("ex");
Exception anEx2 = new RuntimeException("ex");
RuntimeException anEx3 = new RuntimeException("ex");
//Correct usage = The base class goes first
Assert.assertTrue(Exception.class.isAssignableFrom(anEx1.getClass()));
Assert.assertTrue(Exception.class.isAssignableFrom(anEx2.getClass()));
Assert.assertTrue(Exception.class.isAssignableFrom(anEx3.getClass()));
//Incorrect usage = Method parameter is used in the wrong order
Assert.assertTrue(anEx1.getClass().isAssignableFrom(Exception.class));
Assert.assertFalse(anEx2.getClass().isAssignableFrom(Exception.class));
Assert.assertFalse(anEx3.getClass().isAssignableFrom(Exception.class));
}
答案 13 :(得分:-2)
我们在团队中进行的一些测试表明,A.class.isAssignableFrom(B.getClass())
的工作速度比B instanceof A
快。如果您需要在大量元素上进行检查,这可能非常有用。