RFR: 8280035: Use Class.isInstance instead of Class.isAssignableFrom where applicable

Erik Gahlin egahlin at openjdk.java.net
Mon Jan 17 08:31:26 UTC 2022


On Thu, 13 Jan 2022 08:39:04 GMT, Andrey Turbanov <duke at openjdk.java.net> wrote:

>> Method `Class.isAssignableFrom` is often used in form of:
>> 
>>     if (clazz.isAssignableFrom(obj.getClass())) {
>> Such condition could be simplified to more shorter and performarnt code
>> 
>>     if (clazz.isInstance(obj)) {
>>     
>> Replacement is equivalent if it's known that `obj != null`.
>> In JDK codebase there are many such places.
>> 
>> I tried to measure performance via JMH
>> 
>>     Class<?> integerClass = Integer.class;
>>     Class<?> numberClass = Number.class;
>> 
>>     Object integerObject = 45666;
>>     Object doubleObject = 8777d;
>> 
>>     @Benchmark
>>     public boolean integerInteger_isInstance() {
>>         return integerClass.isInstance(integerObject);
>>     }
>> 
>>     @Benchmark
>>     public boolean integerInteger_isAssignableFrom() {
>>         return integerClass.isAssignableFrom(integerObject.getClass());
>>     }
>> 
>>     @Benchmark
>>     public boolean integerDouble_isInstance() {
>>         return integerClass.isInstance(doubleObject);
>>     }
>> 
>>     @Benchmark
>>     public boolean integerDouble_isAssignableFrom() {
>>         return integerClass.isAssignableFrom(doubleObject.getClass());
>>     }
>> 
>>     @Benchmark
>>     public boolean numberDouble_isInstance() {
>>         return numberClass.isInstance(doubleObject);
>>     }
>> 
>>     @Benchmark
>>     public boolean numberDouble_isAssignableFrom() {
>>         return numberClass.isAssignableFrom(doubleObject.getClass());
>>     }
>> 
>>     @Benchmark
>>     public boolean numberInteger_isInstance() {
>>         return numberClass.isInstance(integerObject);
>>     }
>> 
>>     @Benchmark
>>     public boolean numberInteger_isAssignableFrom() {
>>         return numberClass.isAssignableFrom(integerObject.getClass());
>>     }
>> 
>>     @Benchmark
>>     public void numberIntegerDouble_isInstance(Blackhole bh) {
>>         bh.consume(numberClass.isInstance(integerObject));
>>         bh.consume(numberClass.isInstance(doubleObject));
>>     }
>> 
>>     @Benchmark
>>     public void integerIntegerDouble_isAssignableFrom(Blackhole bh) {
>>         bh.consume(integerClass.isAssignableFrom(integerObject.getClass()));
>>         bh.consume(integerClass.isAssignableFrom(doubleObject.getClass()));
>>     }
>> 
>> `isInstance` is a bit faster than `isAssignableFrom`
>> 
>> Benchmark                              Mode  Cnt  Score   Error  Units
>> integerDouble_isAssignableFrom         avgt    5  1,173 ± 0,026  ns/op
>> integerDouble_isInstance               avgt    5  0,939 ± 0,038  ns/op
>> integerIntegerDouble_isAssignableFrom  avgt    5  2,106 ± 0,068  ns/op
>> numberIntegerDouble_isInstance         avgt    5  1,516 ± 0,046  ns/op
>> integerInteger_isAssignableFrom        avgt    5  1,175 ± 0,029  ns/op
>> integerInteger_isInstance              avgt    5  0,886 ± 0,017  ns/op
>> numberDouble_isAssignableFrom          avgt    5  1,172 ± 0,007  ns/op
>> numberDouble_isInstance                avgt    5  0,891 ± 0,030  ns/op
>> numberInteger_isAssignableFrom         avgt    5  1,169 ± 0,014  ns/op
>> numberInteger_isInstance               avgt    5  0,887 ± 0,016  ns/op
>
> src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java line 405:
> 
>> 403:                         Object res = m.invoke(a, new Object[0]);
>> 404:                         if (res instanceof Annotation[]) {
>> 405:                             for (Annotation rep : (Annotation[]) m.invoke(a, new Object[0])) {
> 
> BTW it looks suspicious to have `m.invoke(a, new Object[0])` called again here. Shouldn't it just reuse `res` variable instead?

It looks unnecessary. Please feel free to fix.

-------------

PR: https://git.openjdk.java.net/jdk/pull/7061



More information about the client-libs-dev mailing list