Berbicara dalam hal kinerja:
TL; DR
Gunakan Instance atau instanceof yang memiliki kinerja serupa. isAssignableFrom sedikit lebih lambat.
Diurutkan berdasarkan kinerja:
- isInstance
- instanceof (+ 0,5%)
- isAssignableFrom (+ 2,7%)
Berdasarkan tolok ukur 2000 iterasi pada JAVA 8 Windows x64, dengan 20 iterasi pemanasan.
Dalam teori
Dengan menggunakan bytecode viewer yang lembut, kita dapat menerjemahkan masing-masing operator menjadi bytecode.
Dalam konteks:
package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
JAWA:
b instanceof A;
Bytecode:
getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
JAWA:
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);
JAWA:
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);
Mengukur berapa banyak instruksi bytecode yang digunakan oleh masing-masing operator, kita dapat mengharapkan instance dan Instance menjadi lebih cepat daripada IssignableFrom . Namun, kinerja aktual TIDAK ditentukan oleh bytecode tetapi oleh kode mesin (yang bergantung pada platform). Mari kita lakukan patokan mikro untuk masing-masing operator.
Patokan
Kredit: Seperti yang disarankan oleh @ aleksandr-dubinsky, dan terima kasih kepada @yura untuk memberikan kode dasar, berikut ini adalah patokan JMH (lihat panduan tuning ini ):
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();
}
}
Memberi hasil berikut (skor adalah sejumlah operasi dalam satuan waktu , sehingga semakin tinggi skor semakin baik):
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
Peringatan
- patokannya adalah JVM dan tergantung platform. Karena tidak ada perbedaan signifikan antara setiap operasi, dimungkinkan untuk mendapatkan hasil yang berbeda (dan mungkin urutan yang berbeda!) Pada versi JAVA yang berbeda dan / atau platform seperti Solaris, Mac atau Linux.
- tolok ukur membandingkan kinerja "adalah B sebuah instance dari A" ketika "B meluas A" secara langsung. Jika hierarki kelas lebih dalam dan lebih kompleks (seperti B memanjang X yang memanjang Y yang memanjang Z yang memanjang A), hasilnya mungkin berbeda.
- biasanya disarankan untuk menulis kode terlebih dahulu memilih salah satu operator (yang paling nyaman) dan kemudian membuat profil kode Anda untuk memeriksa apakah ada hambatan kinerja. Mungkin operator ini dapat diabaikan dalam konteks kode Anda, atau mungkin ...
- dalam kaitannya dengan poin sebelumnya,
instanceof
dalam konteks kode Anda mungkin dioptimalkan lebih mudah daripada isInstance
misalnya ...
Untuk memberi Anda contoh, ambil loop berikut:
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;
Berkat JIT, kode ini dioptimalkan pada beberapa titik dan kami mendapatkan:
- instanceof: 6ms
- isInstance: 12ms
- isAssignableFrom: 15ms
Catatan
Awalnya posting ini sedang melakukan benchmark sendiri menggunakan for loop di JAWA mentah, yang memberikan hasil tidak dapat diandalkan karena beberapa optimasi seperti Just In Time dapat menghilangkan loop. Jadi sebagian besar mengukur berapa lama yang dibutuhkan kompiler JIT untuk mengoptimalkan loop: lihat Tes kinerja terlepas dari jumlah iterasi untuk lebih jelasnya
Pertanyaan-pertanyaan Terkait