How is it possible that java.lang.Object is implemented in Java?
You can modify java.lang.Object
(e.g. by adding public static void main()
method), but in order to be loaded and used by the JVM, the modified class needs to be added to the bootstrap class path.
On JDK 8 this can be done with
java -Xbootclasspath/p:<path>
On JDK 9+ this requires patching java.base
module:
java --patch-module java.base=<path>
When the JVM starts, it loads java.lang.Object
by the bootstrap class loader just like any other class, so java.lang.Object
with the added main
method can be actually executed:
$ java -Xbootclasspath/p:. java.lang.Object
Hello world from custom java.lang.Object!
However, if you try to remove existing java.lang.Object
methods, add new virtual methods, add fields or otherwise change the existing layout - this won't work. Most likely, the JVM will just crash with the fatal error.
This is because the JVM expects java.lang.Object
to have the known layout. There are hard-coded offsets in the JVM source code, references to the exiting methods, etc. The same is true for other intrinsic classes like java.lang.String
, java.lang.Class
, java.lang.ref.Reference
and similar.
As to Object's superclass, there is an exception explicitly described in JVM Specification:
If the value of the super_class item is zero, then this class file must represent the class Object, the only class or interface without a direct superclass.
Both Java compiler and the JVM know about this exception, and enforce this rule when compiling Object.java
and when loading Object.class
.
You can implement java.lang.Object
in Java and the actual class you’re using has been indeed created from the Object.java
file that ships with the JDK.
The Java® Language Specification says in Chapter 8. Classes:
Each class except
Object
is an extension of (that is, a subclass of) a single existing class (§8.1.4) and may implement interfaces (§8.1.5).
So the absence of supertypes for Object
is fixed in the language.
You can use the source code of your experiment and try to add an extends
or implements
clause and see that the compiler will reject it.
When you compile the class java.lang.Object
, the resulting class file will be the only one that has no supertype. See The Java® Virtual Machine Specification, §4.1., The ClassFile Structure:
- super_class
For a class, the value of the
super_class
item either must be zero or must be a valid index into theconstant_pool
table. If the value of thesuper_class
item is nonzero, theconstant_pool
entry at that index must be aCONSTANT_Class_info
structure representing the direct superclass of the class defined by thisclass
file. Neither the direct superclass nor any of its superclasses may have theACC_FINAL
flag set in theaccess_flags
item of itsClassFile
structure.If the value of the
super_class
item is zero, then thisclass
file must represent the classObject
, the only class or interface without a direct superclass.For an interface, the value of the
super_class
item must always be a valid index into theconstant_pool
table. Theconstant_pool
entry at that index must be aCONSTANT_Class_info
structure representing the classObject
.
So even interfaces have an entry for the superclass in the class file (pointing to Object
) and the class file for java.lang.Object
is the only one with a zero entry for the super class.
When you try to load your version of the Object
class at runtime, you stumble across the fact that you can’t load classes of the java.lang
package (or any class whose qualified name starts with java.
) through the class path in general.
Prior to Java 9, you would have to set up the bootstrap class path to include your version. Starting with Java 9, the class java.lang.Object
must belong to the java.base
module, which is loaded in an implementation specific manner. You’d have to use the --patch-module
option to inject your own version.
But you have to be careful with what you write into your own version. There are a lot of expectations by other classes and the environment and not meeting them can break it (badly).
JLS, §4.3.2. The Class Object lists the expected methods and links to other chapters that define special language semantics for some of them.
That's a really cool experiment. But this is how Java works
- Since every class in Java has to extend
java.lang.Object
, your customObject
class also extends that. - To load any class, Java needs to load it's parent classes. So when Java tries to run the
main()
method inside your customObject
class, it loads the realjava.lang.Object
class. - As soon as real
java.lang.Object
class is loaded, JVM tries to run themain()
method of that class. Since it doesn't exist, your application fails with.