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 the constant_pool table. If the value of the super_class item is nonzero, the constant_pool entry at that index must be a CONSTANT_Class_info structure representing the direct superclass of the class defined by this class file. Neither the direct superclass nor any of its superclasses may have the ACC_FINAL flag set in the access_flags item of its ClassFile structure.

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.

For an interface, the value of the super_class item must always be a valid index into the constant_pool table. The constant_pool entry at that index must be a CONSTANT_Class_info structure representing the class Object.

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

  1. Since every class in Java has to extend java.lang.Object, your custom Object class also extends that.
  2. To load any class, Java needs to load it's parent classes. So when Java tries to run the main() method inside your custom Object class, it loads the real java.lang.Object class.
  3. As soon as real java.lang.Object class is loaded, JVM tries to run the main() method of that class. Since it doesn't exist, your application fails with.

Tags:

Java

Jvm