Search code examples
javaconstructor.class-file

What happens if I remove the super constructor call from class file?


When a constructor doesn't have a explicit call of the super class constructor (or this()) then the compiler inserts super().

What would happen if this call was removed from the class file (after compilation)?


Solution

  • I tried it myself.

    class Test
    {
        public Test()
        {
            System.out.println("Hello World");
        }
    
        public static void main(String[] args)
        {
            new Test()
        }
    }
    

    I compiled it and removed invokespecial java/lang/Object/<init>()V from the constructor with a class file editor.

    It seems like the JVM refuses to load the class:

    Exception in thread "main" java.lang.VerifyError: Operand stack overflow
    Exception Details:
      Location:
        Test.<init>()V @4: ldc
      Reason:
        Exceeded max stack size.
      Current Frame:
        bci: @4
        flags: { flagThisUninit }
        locals: { uninitializedThis }
        stack: { uninitializedThis, 'java/io/PrintStream' }
      Bytecode:
        0000000: 2ab2 0002 1203 b600 04b1
    
            at java.lang.Class.getDeclaredMethods0(Native Method)
            at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
            at java.lang.Class.getMethod0(Unknown Source)
            at java.lang.Class.getMethod(Unknown Source)
            at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
            at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
    

    I still don't know if that is a defined behaviour.

    EDIT

    According to Raedwald I also have to alter the stack manipulation.

    So I also removed aload_0 which was before the super constructor call.

    Now I get the following exception:

    Exception in thread "main" java.lang.VerifyError: Constructor must call super()
    or this() before return
        Exception Details:
      Location:
        org/exolin/geno/Test.<init>()V @8: return
      Reason:
        Error exists in the bytecode
      Bytecode:
        0000000: b200 0212 03b6 0004 b1
    
            at java.lang.Class.getDeclaredMethods0(Native Method)
            at java.lang.Class.privateGetDeclaredMethods(Unknown Source)
            at java.lang.Class.getMethod0(Unknown Source)
            at java.lang.Class.getMethod(Unknown Source)
            at sun.launcher.LauncherHelper.validateMainClass(Unknown Source)
            at sun.launcher.LauncherHelper.checkAndLoadMain(Unknown Source)
    

    This made me curious so I reordered the constructor instructions to:

    getstatic java/lang/System/out Ljava/io/PrintStream;
    ldc "Message"
    invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
    aload_0
    invokespecial java/lang/Object/<init>()V
    return
    

    Which worked!