-1

Is there a difference, and if yes, then what is the difference between new String[0].getClass() and String[].class?

I am interested in facts like (non-exhaustive list):

  • do both initialise an empty array?
  • is this empty array cached in the JVM?
  • do they operate on the some array-class-object?
  • are they the same on the byte-code level?

Note: Probably it is somehow written in the JLS, but I couldn't find a proper description anywhere.

9
  • Note that new String[0].class is not valid Java syntax. Did you really mean that, or something else? Commented Sep 17, 2018 at 13:46
  • Is this a homework assignment? Commented Sep 17, 2018 at 13:47
  • 1
    The answer to 1,2, and 4 is “No”. For the third point, it’n not clear what you mean. Commented Sep 17, 2018 at 14:00
  • @Jesper: sorry, incorrect syntax fixed Commented Sep 17, 2018 at 14:12
  • @dbl: No, this is a genuine question, which has arisen when we wanted to deserialize arrays from a REST-call (i.e., via readEntity()). Commented Sep 17, 2018 at 14:13

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.