Inside the JVM — Part 03 (ClassLoader Cont…)

Chamal Weerasinghe
4 min readMay 3, 2021

--

Photo by Pat Whelen on Unsplash

“Just keep going. You never know how far you can go - Gunna”

In the previous article, we talked about the ClassLoader process, and I thought breaking up some interesting content into another article to grab things easily. At the end of the JVM loading process initialization, there is an interesting question is that how to find and map the parent classes and how the (*.class) file is managed. Before jumping into that Let’s find out how can we initialize a class

  1. Using new Keyword- Object will use the initial value we pass.
Employee emp = new Employee("John Doe", 34, "Consultant", "p@ssw@4d");

2. Using clone() method — Object will use the attributes of the source class, in this example it’s “emp” (Before calling to the clone method is should override in the child class by winding the accessibility — from “protected” to the “public”)

Employee sameEmp = (Employee) emp.clone();

3. Using reflection API by calling “getInstance()” method- Here also it uses the initial value for initializing the object.

DbConfigs dbConfigsInstance = DbConfigs.getInstance();

4. Using ObjectInputStream- This uses raw data instead of initializing at the beginning, but it uses only the non-transient values. and Transient values will initialize with the default values. This scenario is well explained here.

ObjectInputStream inputStream = new ObjectInputStream(new  FileInputStream("values.txt"));            
Employee employee = (Employee) inputStream.readObject();

But how Java finds the constructors of its parent classes its own constructors at the byte code level?

In Java, there is a method without no name ({ }) it is also known as the “method method”, this method is only created by the compiler if there are any static or instance level variables the “method method” will be created, if there are no static variables and instance variables there will be no “method method” / method without a name.

And also for each and every constructor java compiler creates a <init> method, this <init> method is totally based on the structure of the constructor of the class.
Basically, the init method contains byte code for a particular constructor and the reference to the init method of the immediate parent's <init> method or if it calls to a constructor in the same class it will contain that constructors <init> method,

Yeah, I was just like that the first time 😃, Let’s get our hands dirty and crack open a .class file to validate this scenario.

First, we use a simple class with nothing inside to demonstrate how it’s like when it compiled to byte code. We use class structures like this,

package dev.chamalwr.jvmSample;public class Employee {}

And the resulted byte code will look like this,

Now we can see Even though we did not add a constructor it implicitly creates one. and also creates a <init> method for that default constructor that's a principle of Java. going down further it called to another class's constructor’s <init> method, which’s also a principle of Java that if we did not explicitly “extends” a class it will automatically “extends” the ultimate parent of all classes the “Object” class

Let’s know more about another example with some elements within it, First, let’s create a simple POJO with some variables in it.

package dev.chamalwr.jvmSample;public class Employee{
private String empId;
private String firstName;
private int b_code;
public Employee(){}public Employee(String empId, String firstName, int b_code){
this();
this.empId = empId;
this.firstName = firstName;
this.b_code = b_code;
}
}

Here is the byte code for the above class,

As we can see now we have two constructors and according to the scenario we explained compiler has created two different <init> methods for each one of them, and if you watch closely we can identify how it manages the referencing of other classes and methods in the class file,

For further clarification, Let’s inspect how a class with user inherited class managed to do this mapping for that we create another class.

As you can see this class inherited our previous “Employee.java” as well and it uses parameterized constructor of the superclass, Now when we compile the class and we can see it like this.

Hope now you get a better idea of how these mappings are happening at the JVM level. How it now references the user-created parent classes, how to pass the values, and so on.
For a better explanation check out the link below.

Reference

ClassLoader Zero to Hero 01: https://www.youtube.com/watch?v=CQQzYCjNdIw

ClassLoader Zero to Hero 02: https://www.youtube.com/watch?v=6seSEynl50k

The tool used for reverse bytecode: https://bytecodeviewer.com/

--

--

No responses yet