Nói về hiệu suất:
TL; DR
Sử dụng isinstance hoặc instanceof mà có hiệu suất tương tự. isAssignableFrom hơi chậm.
Sắp xếp theo hiệu suất:
- isinstance
- instanceof (+ 0,5%)
- isAssignableFrom (+ 2,7%)
Dựa trên một chuẩn mực của 2000 lần lặp lại trên JAVA 8 Windows x64, với 20 lần lặp lại.
Về lý thuyết
Sử dụng một phần mềm như bytecode viewer chúng ta có thể dịch mỗi nhà khai thác vào bytecode.
Trong bối cảnh:
package foo;
public class Benchmark
{
public static final Object a = new A();
public static final Object b = new B();
...
}
JAVA:
b instanceof A;
Bytecode:
getstatic foo/Benchmark.b:java.lang.Object
instanceof foo/A
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:
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);
đo bao nhiêu hướng dẫn bytecode được sử dụng bởi mỗi nhà khai thác, chúng ta có thể mong đợi instanceof và isinstance để nhanh hơn isAssignableFrom. Tuy nhiên, hiệu suất thực tế KHÔNG được xác định bởi bytecode mà bởi mã máy (phụ thuộc vào nền tảng). Hãy làm một tiêu chuẩn vi mô cho mỗi nhà điều hành.
Điểm chuẩn
tín dụng: Là cố vấn bởi @ Aleksandr-Dubinsky, và nhờ @yura cho việc cung cấp các mã cơ bản, đây là một chuẩn mực JMH (xem này 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();
}
}
Đưa ra các kết quả sau (điểm số là một số thao tác trong một đơn vị thời gian, vì vậy điểm càng cao càng tốt):
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
- điểm chuẩn là JVM và phụ thuộc nền tảng. Vì không có sự khác biệt đáng kể giữa mỗi hoạt động, có thể có được kết quả khác nhau (và có thể thứ tự khác!) Trên một phiên bản và/hoặc nền tảng JAVA khác như Solaris, Mac hoặc Linux.
- điểm chuẩn so sánh hiệu suất của "là B một thể hiện của A" khi "B mở rộng A" trực tiếp. Nếu phân cấp lớp sâu hơn và phức tạp hơn (như B mở rộng X mở rộng Y mở rộng Z mở rộng A), kết quả có thể khác.
- thường được khuyên nên viết mã trước tiên hãy chọn một toán tử (thuận tiện nhất) và sau đó lập hồ sơ cho mã của bạn để kiểm tra xem có tắc nghẽn hiệu suất hay không. Có thể nhà điều hành này không đáng kể trong bối cảnh mã của bạn hoặc có thể ...
- liên quan đến điểm trước đó,
instanceof
trong ngữ cảnh mã của bạn có thể được tối ưu hóa dễ dàng hơn ví dụ isInstance
...
Để cung cấp cho bạn một ví dụ, đi vòng lặp sau:
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;
Nhờ JIT, các mã được tối ưu hóa tại một số điểm và chúng tôi nhận được:
- instanceof: 6ms
- isInstance: 12ms
- isAssignableTừ: 15ms
Note
Nguyên bài này được làm chuẩn riêng của mình bằng cách sử dụng cho vòng lặp trong JAVA liệu, trong đó đã cho kết quả không đáng tin cậy như một số tối ưu hóa như Just In Time có thể loại bỏ các vòng lặp. Vì vậy, nó đã được chủ yếu là đo bao lâu đã làm trình biên dịch JIT làm để tối ưu hóa vòng lặp: xem Performance test independent of the number of iterations để biết thêm chi tiết
câu hỏi liên quan
Đối với các bản ghi, isInstance() là phương pháp thuận tiện nhất để kiểm tra xem một đối tượng có thể được đúc thành loại lớp hay không (để biết thêm chi tiết, xem: http://tshikatshikaaa.blogspot.nl /2012/07/java-instanceof-isassignablefrom-or.html) – JVerstry