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

Andrey Turbanov duke at openjdk.java.net
Fri Jan 14 18:01:01 UTC 2022


On Thu, 13 Jan 2022 08:25:22 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?

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

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



More information about the client-libs-dev mailing list