-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.

D. Kovács
  • 1,232
  • 13
  • 25
  • Note that `new String[0].class` is not valid Java syntax. Did you really mean that, or something else? – Jesper Sep 17 '18 at 13:46
  • Is this a homework assignment? – dbl Sep 17 '18 at 13:47
  • 1
    The answer to 1,2, and 4 is “No”. For the third point, it’n not clear what you mean. – Holger Sep 17 '18 at 14:00
  • @Jesper: sorry, incorrect syntax fixed – D. Kovács Sep 17 '18 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()`). – D. Kovács Sep 17 '18 at 14:13
  • @Holger: could you elaborate please? The questions, as I have written are just examples, not exhaustive list. Are you sure for example that the second does not initialize an array-object? For the third question: static methods and variables are bound to the class-object not the instance-objects. I can imagine, that the `.class` is bound on a type-based array-object and not on the array-instance itself. – D. Kovács Sep 17 '18 at 14:16
  • For the negative votes: I would be glad, if you could leave a couple comments, why is this a bad question? It is a genuine question about Java internals. – D. Kovács Sep 17 '18 at 14:16
  • Well, `new String[0].getClass()` gets compiled as written, instructions to create a new array, followed by a method invocation of `getClass()`, whereas the class literal gets compiled to a single `ldc` instruction (see “[How is a class literal compiled to Java bytecode?](https://stackoverflow.com/a/46060724/2711488)”). Then, consider that the `new` operator is *guaranteed* to produce a new object with a distinct identity, i.e. `new String[0] != new String[0]`, and you can answer most of your questions yourself. – Holger Sep 17 '18 at 14:40
  • @Holger: does that hold 1-to-1 for array type literals too? If yes, could you please write it up as an answer, so I can accept it? – D. Kovács Sep 17 '18 at 15:07

1 Answers1

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.

Holger
  • 285,553
  • 42
  • 434
  • 765