Java question about a .class generated with Java 14

I have a simple class like this:

class ClassWithDefaultConstructor{}

I am working with this JDK:

C:\JavaSE14Folder>java -version
java version "14" 2020-03-17
Java(TM) SE Runtime Environment (build 14+36-1461)
Java HotSpot(TM) 64-Bit Server VM (build 14+36-1461, mixed mode, sharing)

As you can see I am using the latest version of the JDK.

I create this .class like this:

C:\JavaSE14Folder>javac -d . ClassWithDefaultConstructor.java

The .class is created later on i try this command:

C:\JavaSE14Folder>javap ClassWithDefaultConstructor.class

And I see the following:

Compiled from "ClassWithDefaultConstructor.java"
class ClassWithDefaultConstructor {
   ClassWithDefaultConstructor();
}

Two things here made me happy; first the default constructor is created and I see that the visibility of the constructor is the same of the class, but three things made feel sad.

My questions are:

  1. Why the constructor has no body and terminates with ;?
  2. Why the constructor hasn't a call to the java.lang.Object constructor?
  3. Why this class is not extending java.lang.Object?

I did expect something like this:

class ClassWithDefaultConstructor extends java.lang.Object {
   ClassWithDefaultConstructor(){
       super();
   }
}

I expected a bytecode something like this post:

Post

Did I miss something?

If I put the command like this:

C:\JavaSE14Folder>javap -c ClassWithDefaultConstructor.class
Compiled from "ClassWithDefaultConstructor.java"
class ClassWithDefaultConstructor {
 ClassWithDefaultConstructor();
 Code:
   0: aload_0
   1: invokespecial #1                  // Method java/lang/Object." 
<init>":
()V
   4: return
}

Is different but still I don't see my stuff like extending Object and so.

I would love see something like this at least like in the post:

Compiled from "test.java"
public class test extends java.lang.Object{

In summary, I don't see the compiler inserting those implicit lines.

In this Java Question about a .class generated with Java 14 states that happens the same on the newer versions of Java.

Same output using:

C:\Program Files\Java\jdk1.8.0_121\bin

Solution 1:

Bytecode != Java source code.

What is actually in the classfile is just random bytes. What you are seeing is javap's textual representation of the bytecode, which is designed to be familiar to Java programmers who don't know much about bytecode, and hence uses Java like syntax where possible. But it is not and is not meant to be actual Java source code.

If you used a different disassembler such as Krakatau, the output would look very different, but it would still be a representation of the same binary classfile.

Solution 2:

From javap's documentation:
"The javap command disassembles one or more class files."

It does not decompile the class file, that is, it is not intended to create valid java source code.

"1. Why the constructor has no body and terminates with ;?"
it is not decompiled code, not valid Java, just an indication there is such constructor.

"2. Why the constructor hasn't a call to the java.lang.Object constructor?"
it is being omitted by javap, but it is there, displayed if correct options were used (see below).

"3. Why this class is not extending java.lang.Object?"
same as previous, it is, just not displayed by javap.

To see more details, we must add the -v (verbose) option to the javap call. Here the output if using javap -c -v ClassWithDefaultConstructor (line numbers added by me):

1   Classfile /C:/tmp/ClassWithDefaultConstructor.class
2     Last modified 16 Jan 2022; size 228 bytes
3     SHA-256 checksum 101973fdf86b3e7facf263214f6932a9353ef7be914efec9963be3a578b3ddaf
4     Compiled from "ClassWithDefaultConstructor.java"
5   class ClassWithDefaultConstructor
6     minor version: 0
7     major version: 61
8     flags: (0x0020) ACC_SUPER
9     this_class: #7                          // ClassWithDefaultConstructor
10    super_class: #2                         // java/lang/Object
11    interfaces: 0, fields: 0, methods: 1, attributes: 1
12  Constant pool:
13     #1 = Methodref          #2.#3          // java/lang/Object."<init>":()V
14     #2 = Class              #4             // java/lang/Object
15     #3 = NameAndType        #5:#6          // "<init>":()V
16     #4 = Utf8               java/lang/Object
17     #5 = Utf8               <init>
18     #6 = Utf8               ()V
19     #7 = Class              #8             // ClassWithDefaultConstructor
20     #8 = Utf8               ClassWithDefaultConstructor
21     #9 = Utf8               Code
22    #10 = Utf8               LineNumberTable
23    #11 = Utf8               SourceFile
24    #12 = Utf8               ClassWithDefaultConstructor.java
25  {
26    ClassWithDefaultConstructor();
27      descriptor: ()V
28      flags: (0x0000)
29      Code:
30        stack=1, locals=1, args_size=1
31           0: aload_0
32           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
33           4: return
34        LineNumberTable:
35          line 1: 0
36  }
37  SourceFile: "ClassWithDefaultConstructor.java"

line number 10: super_class: #2 // java/lang/Object
gives us the super class, that is, Object

line number 32: 1: invokespecial #1 // Method java/lang/Object."<init>":()V
this is calling the constructor of Object for the actual instance (previous line aload_0=this) - <init> is the name used for constructors (independent of class name) - that is the equivalent to super().