The expression new String[0].getClass()
gets straight-forwardly compiled to instructions to create a new array, followed by a method invocation of getClass()
. In contrast, the class literal String[].class
gets compiled to a single ldc
instruction, as elaborated in “How is a class literal compiled to Java bytecode?”.
You can verify this by running the following program
package jvm;
import javax.tools.ToolProvider;
public class GetArrayClass {
public static Class<?> viaGetClass() {
return new String[0].getClass();
}
public static Class<?> viaClassLiteral() {
return String[].class;
}
public static void main(String[] args) {
decompile();
}
private static void decompile() {
Object args = new String[]{"-c", GetArrayClass.class.getName()};
try {
ToolProvider.getSystemJavaCompiler().getClass().getClassLoader()
.loadClass("com.sun.tools.javap.Main")
.getMethod("main", String[].class).invoke(null, args);
} catch(ReflectiveOperationException ex) {
throw new IllegalStateException(ex);
}
}
private GetArrayClass(){}
}
Demo on Ideone
public static java.lang.Class<?> viaGetClass();
Code:
0: iconst_0
1: anewarray #1 // class java/lang/String
4: invokevirtual #2 // Method java/lang/Object.getClass:()Ljava/lang/Class;
7: areturn
public static java.lang.Class<?> viaClassLiteral();
Code:
0: ldc #3 // class "[Ljava/lang/String;"
2: areturn
The expression new String[0]
can not get replaced by a shared array, as the new
operator is guaranteed to produce a new object with a distinct identity, i.e. new String[0] != new String[0]
. But in a use case like this, where the instance is temporary and no identity sensitive operations are performed, chances are high that the JVM’s optimizer will eliminate the allocation, in case it becomes a hot spot.