I wonder if there is a difference between:
String a = (String) arg;
and cast class:
String a = String.class.cast(arg);
I once heard that using the static cast class is more performative, is this true?
I wonder if there is a difference between:
String a = (String) arg;
and cast class:
String a = String.class.cast(arg);
I once heard that using the static cast class is more performative, is this true?
Both execute the same task, but the so-called "static" version generates more bytecode (more overhead at compile time).
In practice both cast using the bytecode statement:
CHECKCAST java/lang/String
The difference that the code generated by the "static" version gets the type declaratively, in the String.class case, making a 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 "static" cast:
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
Thus:
LDC Ljava/lang/String;.class
The above statement returns an instance of Class
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 it can be seen in the bytecode that calling the Class.cast (object) is done using the INVOKEVIRTUAL statement and not INVOKESTATIC.
As said by Felipe in the comments, for comparative performance issues you just have to do a simple benchmarking of the two approaches.
In this example we used Metrics , version 3.1.0
. If you use maven , simply add this dependency:
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>3.1.0</version>
</dependency>
Other considerations:
10000 casts of objects to String
, both using cast operator , and using cast(Object obj)
.
Below are the excerpts used for cast:
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
cast(Object obj)
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.
From the result we can see that there is a significant difference, that is, we can conclude that this is not treated differently by the compiler.
Now, let's look at the bytecode generated in both approaches:
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
cast(Object obj)
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
Bytecode we can see that in fact using cast operator is more costly, if you check each statement in specification you will see in detail why this.
In summary it's because java knows the type just at runtime, so it has to turn around to make sure it does not give a ClassCastException
. Already in the other approach, even generating more bytecode , you already left explicit the type you expect, if it is not ( isInstance(Object obj)
) a ClassCastException
will be released, without the JVM seeking more information to try the cast
Already knowing that there are differences in performance, are there advantages and disadvantages? I can now remember only when we use generics:
String
), ie instead: @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);
}