CAST: difference between "(String) Arg" and "String.class.cast(Arg)"

Asked

Viewed 145 times

7

I wonder if there’s a difference between:

String a = (String) arg;

and the cast class:

String a = String.class.cast(arg);

I once heard that using the cast static class is more performatic, this is true?

  • 2

    I think you can make bechmarking and find out.

2 answers

6


Both run the same task, but the so-called "static" version generates more bytecode (more overhead at compile time).

In practice both run the cast using bytecode instruction:

CHECKCAST java/lang/String

The difference that the code generated by the "static" version gets the type declaratively, in the case of String.class, by making a call from Class.cast(Object)

reference code:

public class CastTest2 {

    public static void main(String... args) {

        Object arg = "Test";

        String explicitCast = (String) arg;

        String explicitDynCast = String.class.cast(arg);

    }

bytecode generated for direct cast:

   L1
    LINENUMBER 10 L1
    ALOAD 1
    CHECKCAST java/lang/String
    ASTORE 2

bytecode generated for cast "statico":

   L2
    LINENUMBER 12 L2
    LDC Ljava/lang/String;.class
    ALOAD 1
    INVOKEVIRTUAL java/lang/Class.cast (Ljava/lang/Object;)Ljava/lang/Object;
    CHECKCAST java/lang/String
    ASTORE 3

So:

LDC Ljava/lang/String;.class

The above statement returns a Class instance

which in turn, calls the cast method, returning an Object:

INVOKEVIRTUAL java/lang/Class.cast (Ljava/lang/Object;)Ljava/lang/Object;

and implicitly does Cast for Type, Class T.

CHECKCAST java/lang/String

ps: The fact that I call "static" and how can be seen in the bytecode that the call to Class.cast(Object) is made using the INVOKEVIRTUAL and not INVOKESTATIC statement.

3

As said by Felipe in the comments, for comparison of performance just you do a benchmarking simple of the two approaches.

In this example was used the Metrics, version 3.1.0. If use , just add this dependency:

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <version>3.1.0</version>
</dependency>

Other considerations:

  • JRE 1.8 update 45
  • Windows 8.1 Pro
  • Shot on Eclipse Luna, release 2, version 4.4.2, Build id 20150219-0600

Were made 10000 Casts of objects to String, both using the cast Operator, how much using cast(Object obj).

Below are the snippets used for cast:

  • using cast Operator
static void usingCastMethod() {
    final Object obj = "string";
    for (int i = 0; i < 10000; i++) {
        final String str = String.class.cast(obj);
    }
}

Result: 629.19 milliseconds

static void usingCastOperator() {
    final Object obj = "string";
    for (int i = 0; i < 10000; i++) {
        final String str = (String) obj;
    }
}

Result: 3065.02 milliseconds

Obs.: the result is only for comparison, just to see that there is a difference in performance.

By the result we can realize that there is significant difference, ie we can conclude that this is not treated differently by the compiler.

Now, let’s see how the bytecode generated in both approaches:

  • using cast Operator
  static void usingCastMethod();
    Code:
       0: ldc           #104                // String string
       2: astore_0
       3: iconst_0
       4: istore_1
       5: goto          21
       8: ldc           #106                // class java/lang/String
      10: aload_0
      11: invokevirtual #113                // Method java/lang/Class.cast:(Ljava/lang/Object;)Ljava/lang/Object;
      14: checkcast     #106                // class java/lang/String
      17: astore_2
      18: iinc          1, 1
      21: iload_1
      22: sipush        10000
      25: if_icmplt     8
      28: return
  static void usingCastOperator();
    Code:
       0: ldc           #104                // String string
       2: astore_0
       3: iconst_0
       4: istore_1
       5: goto          16
       8: aload_0
       9: checkcast     #106                // class java/lang/String
      12: astore_2
      13: iinc          1, 1
      16: iload_1
      17: sipush        10000
      20: if_icmplt     8
      23: return

By bytecode we can see that actually using cast Operator is more expensive, if you check every instruction in specification you will see in detail why.

In short it is due to the fact that java knows the type only at runtime, so it has to turn around to ensure as much as possible that it does not give a ClassCastException. Already in the other approach, even generating more bytecode, you’ve already made explicit the kind that waits, if not him (isInstance(Object obj)) one ClassCastException will be launched, without the JVM seeking more information to try the cast

Knowing that in terms of performance there is a difference, there are advantages and disadvantages? I can now remember only when we use generics:

  • to avoid Warning at compile time when we are using generics (and not just String), that is, instead of this:
@SuppressWarnings("unchecked")
public <T> T cast(final Object o) {
    return (T) o;
}

Prefer to use this:

public <T> T cast(final Class<T> clazz, final Object o) {
    return clazz.cast(o);
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.