instanceof和Class.isAssignableFrom(...)有什麼區別?

本文翻譯自:What is the difference between instanceof and Class.isAssignableFrom(…)?

Which of the following is better? 以下哪項更好?

a instanceof B

or 要麼

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

The only difference that I know of is, when 'a' is null, the first returns false, while the second throws an exception. 我所知道的唯一區別是,當'a'爲null時,第一個返回false,而第二個拋出異常。 Other than that, do they always give the same result? 除此之外,他們總是給出相同的結果嗎?


#1樓

參考:https://stackoom.com/question/25Gy/instanceof和Class-isAssignableFrom-有什麼區別


#2樓

Talking in terms of performance : 談論績效:

TL;DR TL; DR

Use isInstance or instanceof which have similar performance. 使用具有類似性能的isInstanceinstanceof isAssignableFrom is slightly slower. isAssignableFrom略慢。

Sorted by performance: 按性能排序:

  1. isInstance isInstance
  2. instanceof (+ 0.5%) instanceof (+ 0.5%)
  3. isAssignableFrom (+ 2.7%) isAssignableFrom (+ 2.7%)

Based on a benchmark of 2000 iterations on JAVA 8 Windows x64, with 20 warmup iterations. 基於JAVA 8 Windows x64上2000次迭代的基準測試,有20次預熱迭代。

In theory 理論上

Using a soft like bytecode viewer we can translate each operator into bytecode. 使用類似軟的字節碼查看器,我們可以將每個運算符轉換爲字節碼。

In the context of: 在以下情況下:

package foo;

public class Benchmark
{
  public static final Object a = new A();
  public static final Object b = new B();

  ...

}

JAVA: JAVA:

b instanceof A;

Bytecode: 字節碼:

getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A

JAVA: JAVA:

A.class.isInstance(b);

Bytecode: 字節碼:

ldc Lfoo/A; (org.objectweb.asm.Type)
getstatic foo/Benchmark.b:java.lang.Object
invokevirtual java/lang/Class isInstance((Ljava/lang/Object;)Z);

JAVA: JAVA:

A.class.isAssignableFrom(b.getClass());

Bytecode: 字節碼:

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

Measuring how many bytecode instructions are used by each operator, we could expect instanceof and isInstance to be faster than isAssignableFrom . 測量每個運算符使用的字節碼指令的數量,我們可以預期instanceofisInstanceisAssignableFrom更快。 However, the actual performance is NOT determined by the bytecode but by the machine code (which is platform dependent). 但是,實際性能不是由字節碼決定的,而是由機器代碼決定的(取決於平臺)。 Let's do a micro benchmark for each of the operators. 讓我們爲每個運營商做一個微基準測試。

The benchmark 基準

Credit: As advised by @aleksandr-dubinsky, and thanks to @yura for providing the base code, here is a JMH benchmark (see this tuning guide ): 信用:正如@ 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();
    }
}

Gave the following results (score is a number of operations in a time unit , so the higher the score the better): 給出以下結果(得分是一個時間單位的操作數 ,所以得分越高越好):

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

Warning 警告

  • the benchmark is JVM and platform dependent. 該基準測試依賴於JVM和平臺。 Since there are no significant differences between each operation, it might be possible to get a different result (and maybe different order!) on a different JAVA version and/or platforms like Solaris, Mac or Linux. 由於每個操作之間沒有顯着差異,因此可能在不同的JAVA版本和/或Solaris,Mac或Linux等平臺上獲得不同的結果(可能是不同的順序!)。
  • the benchmark compares the performance of "is B an instance of A" when "B extends A" directly. 基準比較直接“B擴展A”時“是B實例”的性能。 If the class hierarchy is deeper and more complex (like B extends X which extends Y which extends Z which extends A), results might be different. 如果類層次結構更深且更復雜(如B擴展X擴展Y,擴展Z擴展A),結果可能不同。
  • it is usually advised to write the code first picking one of the operators (the most convenient) and then profile your code to check if there are a performance bottleneck. 通常建議首先選擇一個操作符(最方便的)編寫代碼,然後分析代碼以檢查是否存在性能瓶頸。 Maybe this operator is negligible in the context of your code, or maybe... 也許這個運算符在代碼的上下文中可以忽略不計,或者......
  • in relation to the previous point, instanceof in the context of your code might get optimized more easily than an isInstance for example... 與前一點相關,代碼上下文中的instanceof可能比isInstance更容易優化,例如......

To give you an example, take the following loop: 舉個例子,採取以下循環:

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;

Thanks to the JIT, the code is optimized at some point and we get: 感謝JIT,代碼在某些時候進行了優化,我們得到:

  • instanceof: 6ms instanceof:6ms
  • isInstance: 12ms isInstance:12ms
  • isAssignableFrom : 15ms isAssignable來自:15ms

Note 注意

Originally this post was doing its own benchmark using a for loop in raw JAVA, which gave unreliable results as some optimization like Just In Time can eliminate the loop. 最初這篇文章是在原始JAVA中使用for循環進行自己的基準測試,由於像Just In Time這樣的優化可以消除循環,因此產生了不可靠的結果。 So it was mostly measuring how long did the JIT compiler take to optimize the loop: see Performance test independent of the number of iterations for more details 因此,它主要測量JIT編譯器優化循環所需的時間:請參閱性能測試,與迭代次數無關,以獲取更多詳細信息

Related questions 相關問題


#3樓

instanceof cannot be used with primitive types or generic types either. instanceof也不能與基本類型或泛型類型一起使用。 As in the following code: 如下面的代碼所示:

//Define Class< T > type ... 

Object e = new Object();

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

The error is: Cannot perform instanceof check against type parameter T. Use it's erasure Object instead since further generic type information will be erased at runtime. 錯誤是:無法對類型參數T執行instanceof檢查。使用它的擦除對象,因爲將在運行時擦除其他泛型類型信息。

Does not compile due to type erasure removing the runtime reference. 由於類型擦除刪除運行時引用而無法編譯。 However, the code below will compile: 但是,下面的代碼將編譯:

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

#4樓

Consider following situation. 考慮以下情況。 Suppose you want to check whether type A is a super class of the type of obj, you can go either 假設你要檢查類型A是否是obj類型的超類,你可以去

... A.class.isAssignableFrom(obj.getClass()) ... ... A.class.isAssignableFrom(obj.getClass())...

OR 要麼

... obj instanceof A ... ... obj instanceof A ...

But the isAssignableFrom solution requires that the type of obj be visible here. 但isAssignableFrom解決方案要求obj的類型在這裏可見。 If this is not the case (eg, the type of obj might be of a private inner class), this option is out. 如果不是這種情況(例如,obj的類型可能是私有內部類),則此選項不存在。 However, the instanceof solution would always work. 但是,解決方案的實例始終有效。


#5樓

some tests we did in our team show that A.class.isAssignableFrom(B.getClass()) works faster than B instanceof A . 我們在團隊中進行的一些測試表明, A.class.isAssignableFrom(B.getClass())工作速度比B instanceof A快。 this can be very useful if you need to check this on large number of elements. 如果您需要在大量元素上進行檢查,這可能非常有用。


#6樓

isAssignableFrom(A, B) =

if (A == B) return true
else if (B == java.lang.Object) return false
else return isAssignableFrom(A, getSuperClass(B))

The pseudo code above is a definition of, if references of type/class A is assignable from references of type/class B. It is a recursive definition. 如果類型/類A的引用可以從類型/類B的引用分配,則上面的僞代碼是定義。它是遞歸定義。 To some it may be helpful, for others it may be confusing. 對某些人來說,這可能會有所幫助,對於其 I add it in case somebody should find it useful. 我添加它以防有人應該發現它有用。 This is just an attempt to capture my understanding, it is not the official definition. 這只是爲了捕捉我的理解,它不是官方的定義。 It is used in a certain Java VM implementation and works for many example programs, so while I cannot guarentee that it captures all aspects of isAssignableFrom, it is not completely off. 它用於某個Java VM實現並適用於許多示例程序,因此雖然我不能保證它捕獲了isAssignableFrom的所有方面,但它並沒有完全關閉。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章