当前位置:  开发笔记 > 编程语言 > 正文

instanceof和Class.isAssignableFrom(...)有什么区别?

如何解决《instanceof和Class.isAssignableFrom()有什么区别?》经验,为你挑选了9个好方法。

以下哪项更好?

a instanceof B

要么

B.class.isAssignableFrom(a.getClass())

我所知道的唯一区别是,当'a'为null时,第一个返回false,而第二个抛出异常.除此之外,他们总是给出相同的结果吗?



1> Marc Novakow..:

使用时instanceof,您需要知道B编译时的类.使用isAssignableFrom()它时可以是动态的,并在运行时更改.


语法是`一个Bref`的实例,而不是一个Bref.class的实例.instanceof运算符的第二个参数是类名,而不是解析为类对象实例的表达式.
我不明白 - 请详细说明**为什么**我们不能写`一个实例的Bref.getClass()`.如果这么少的解释(或缺乏解释),这怎么能成为公认的答案呢?
是的,"动态"不言而喻:)除了性能,这是一个真正的区别.
@EliranMalka也许你可以拥有一个在运行时生成的类.像代理对象一样.

2> Adam Rosenfi..:

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).


我没有看到使用instanceof/isAssignableFrom与原始类型的关键.

3> JBE..:

谈论绩效:

TL; DR

使用具有类似性能的isInstanceinstanceof.isAssignableFrom略慢.

按性能排序:

    isInstance

    instanceof(+ 0.5%)

    isAssignableFrom(+ 2.7%)

基于JAVA 8 Windows x64上2000次迭代的基准测试,有20次预热迭代.

理论上

使用类似软的字节码查看器,我们可以将每个运算符转换为字节码.

在以下情况下:

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);

测量每个运算符使用的字节码指令的数量,我们可以预期instanceofisInstanceisAssignableFrom更快.但是,实际性能不是由字节码决定的,而是由机器代码决定的(取决于平台).让我们为每个运营商做一个微基准测试.

基准

信用:正如@ aleksandr-dubinsky所建议的,并且感谢@yura提供基本代码,这里有一个JMH基准测试(参见本调优指南):

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

警告

该基准测试依赖于JVM和平台.由于每个操作之间没有显着差异,因此可能在不同的JAVA版本和/或Solaris,Mac或Linux等平台上获得不同的结果(可能是不同的顺序!).

基准比较直接"B扩展A"时"是B实例"的性能.如果类层次结构更深且更复杂(如B扩展X扩展Y,扩展Z扩展A),结果可能不同.

通常建议首先选择一个操作符(最方便的)编写代码,然后分析代码以检查是否存在性能瓶颈.也许这个运算符在代码的上下文中可以忽略不计,或者......

与前一点相关,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

感谢JIT,代码在某些时候进行了优化,我们得到:

instanceof:6ms

isInstance:12ms

isAssignable来自:15ms

注意

最初这篇文章是在原始JAVA中使用for循环进行自己的基准测试,由于像Just In Time这样的优化可以消除循环,因此产生了不可靠的结果.因此,它主要测量JIT编译器优化循环所需的时间:请参阅性能测试,与迭代次数无关,以获取更多详细信息

相关问题

instanceof运算符是否会产生大量开销?为什么?

如何在JAVA中实现instanceof?

在Java中使用instanceof的性能影响


是的,`instanceof`是一个字节码,它使用与`checkcast`(铸造背后的字节码)基本相同的逻辑.无论JITC优化程度如何,它本身都会比其他选项更快.
不要编写自己的微基准测试!使用JMH.

4> user102008..:

更直接的相当于a instanceof B

B.class.isInstance(a)

当此作品(返回false)anull也.



5> 小智..:

除了上面提到的基本差异之外,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.


`b instanceof A`相当于`A.class.isAssignableFrom(b.getClass())`(正如OP注意到的那样).你的例子是正确但无关紧要的.
为什么在此示例中为“ b.getClass()。isAssignableFrom(A.class)”?我猜例子应该是反向的A.class.isAssignableFrom(b.getClass())。

6> 小智..:

还有另一个区别:

null instanceof X false无论X是什么

null.getClass().isAssignableFrom(X)将抛出NullPointerException


-1,不正确:`null instanceof X`(其中X是编译时已知的某个类)将始终返回`false`.
@Caspar虽然你是对的,但基本的想法是个好点.我编辑了帖子,这是正确的.

7> 小智..:

还有另一个不同之处.如果要测试的类型(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
}

哎呀,我看到这个答案已经涵盖了.也许这个例子对某人有帮助.


实际上没有答案是真的正确isAssignableFrom工作w /类,Class.isInstance是*'instanceof'的模拟*

8> 小智..:

这个主题为我提供了一些instanceof有所不同的见解isAssignableFrom,所以我想我会分享一些自己的东西.

我发现isAssignableFrom如果一个类的引用可以接受另一个类的实例,当一个类没有类的实例进行比较时,使用它是唯一的(可能不是唯一的,但可能是最简单的)方式来询问自己.

因此,我没有发现使用instanceof运算符来比较赋值是一个好主意,当我所有的都是类时,除非我考虑从其中一个类创建一个实例; 我以为这会马虎.



9> James Drinka..:

instanceof不能与基本类型或泛型类型一起使用。如以下代码所示:

//Define Class< T > type ... 

Object e = new Object();

if(e instanceof T) {
  // Do something.
}

错误是:无法对类型参数T执行instanceof检查。请改用它的擦除对象,因为在运行时将删除更多的通用类型信息。

由于类型删除导致无法编译,因此删除了运行时引用。但是,下面的代码将编译:

if( type.isAssignableFrom(e.getClass())){
  // Do something.
}

推荐阅读
Chloemw
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有