Loading order of Java classes and JVM parental delegation model

Posted by bobdabuilder on Wed, 13 Oct 2021 04:31:46 +0200

reference resources
In depth understanding of the creation process of Java objects: class initialization and instantiation
Deep JVM parental delegation model
[jvm] take JDBC as an example to talk about the destruction of parental delegation model
Why should the loading mechanism of two parent delegation be adopted for JVM class loading?

Java object creation method

The parent class code and child class code are as follows:

//Parent class
public class SuperClass {

    private String name;

    private static int age;

    {
        name = "hh";
        System.out.println("Parent class.. Initializes the instance block..");
    }

    static {
        age = 18;
        System.out.println("Parent class.. Initialize static code block..");
    }

    public SuperClass(String name) {
        System.out.println("Parent class.. There are parameter constructors..");
        this.name = name;
    }

    public SuperClass() {
        System.out.println("Parent class.. Parameterless constructor..");
    }

    @Override
    public String toString() {
        return "SuperClass{" +
                "name='" + name + '\'' +
                "age" + age + '\'' +
                '}';
    }
}

//Subclass
public class SubClass extends SuperClass {
    private String company;

    private static String phone;

    {
        company = "wangwang";
        System.out.println("Subclass.. Initializes the instance block..");
    }

    static {
        phone = "1888888888";
        System.out.println("Subclass.. Initialize static code block..");
    }

    public SubClass(String name, String company) {
        super(name);
        this.company = company;
        System.out.println("Subclass.. Parameter constructor 1..");
    }

    public SubClass(String company) {
        this.company = company;
        System.out.println("Subclass.. Parameter constructor 2..");
    }

    public SubClass() {
        System.out.println("Subclass.. Parameterless constructor..");
    }

    @Override
    public String toString() {
        return super.toString() + "SubClass{" +
                "company='" + company + '\'' +
                "phone='" + phone + '\'' +
                '}';
    }
}

  1. Use the new keyword
SubClass subClass = new SubClass("Willow","niu");
  1. Use the newInstance method of Class (reflection mechanism)

The newInstance method calls the parameterless constructor to create an object

SubClass subClass = (SubClass) Class.forName("com.bean.SubClass").newInstance();
SubClass subClass = SubClass.class.newInstance();
  1. Use newInstance method of Constructor class (reflection mechanism)

This method is very similar to the newInstance method in Class, but the newInstance of Constructor Class can call parameterized and private constructors

Constructor<SubClass> constructor = SubClass.class
                .getConstructor(String.class);
SubClass subClass = constructor.newInstance("Willow");
  1. Using Clone

When calling clone() method: 1. The object must inherit clonable. 2. The clone method must be overloaded.

//Inherit + override clone(), others are the same as above
public class SubClass extends SuperClass implements Cloneable {
   
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

//Called on Creation
SubClass subClass = new SubClass("Willow","niu");
SubClass subClass2 = (SubClass) subClass.clone();
  1. Using the (DE) serialization mechanism

When an object is deserialized, the JVM creates a separate object and does not call any constructors. In order to deserialize an object, the class must implement the Serializable interface.

The parent class implements the Serializable interface

public class SuperClass implements Serializable 

Deserialize object

    public static void main(String[] args) throws Exception {
        SubClass subClass = new SubClass("Willow","Willow's company");
        ObjectOutputStream output = new ObjectOutputStream(
                new FileOutputStream("SubClass.txt"));
        output.writeObject(subClass);
        output.close();

        System.out.println(subClass);
        System.out.println("***********************");

        ObjectInputStream input = new ObjectInputStream(new FileInputStream(
                "SubClass.txt"));
        SubClass outSubClass = (SubClass) input.readObject();
        System.out.println(outSubClass);
        input.close();
    }

Output results

Loading order of classes

The virtual machine design team implements the action of "obtaining the binary byte stream describing this class through the fully qualified name of a class" in the class loading stage outside the java virtual machine, so that the application can decide how to obtain the required classes. The code module that implements this action is called "class loader"

Class loader is to find class or interface bytecode files to parse and construct components represented by objects inside the JVM. In java, the class loader loads a class into the JVM through the following steps:

  1. Loading: finding and importing Class files
  2. Link: the parsing steps are optional (a) check: check the correctness of the loaded class file data (b) preparation: allocate storage space to the static variables of the class
    (c) Resolve: convert symbolic references to direct references
  3. Initialization: initialize static variables and static code blocks
public class Demo1Application {
    public static void main(String[] args) throws Exception {
        SubClass subClass = new SubClass("Willow","niu");
        System.out.println(subClass);
    }
}

The results are as follows:

In the class, the loading order is:
1. First load the static field or static statement block of the parent class.
2. Static field or static statement block of subclass.
3. Parent class common variables and statement blocks.
4. The parent class constructor is loaded.
5. Subclass variables or statement blocks are loaded.
6. The subclass construction method is loaded.
Static methods are loaded only when they are called, but not when they are not called.
The order in which static statement blocks and static variables are initialized is related to the code order.

JVM parental delegation model

JVM parental delegation model: if a class loader receives a class loading request, it will not load the class immediately, but delegate the request to the parent class loader to load the class. Finally, the loading request will be sent to the boot class loader. Only when the parent class loader cannot complete the loading request (that is, there is no such class in the search scope), The child loader will try to load the class itself.

Why should the JVM load classes using the two parent delegation model?

Based on the design of the parent delegation model, the problem that the basic class in Java, Object, is similar to the Object class repeated many times will not exist, because after layer by layer transmission, the loading request will eventually be responded by the Bootstrap ClassLoader. There will also be only one loaded Object class. Otherwise, if the user writes a java.lang.Object class and puts it into ClassPath, there will be many Object classes. In this way, the most basic behavior in the Java type system can not be guaranteed, and the application will be confused.

Benefits of the parental delegation model:
1. Security to avoid the dynamic replacement of some core classes of JAVA by classes written by users themselves.
2. Avoid the repeated loading of classes, because different classes are distinguished in the JVM, not just according to the class name. The same class file is loaded by different classloaders, which is two different classes.

In the JVM, there are two necessary conditions to indicate whether two class objects are the same class object:
1. The fully qualified name of the class must be consistent, including the package name.
2. The ClassLoader (ClassLoader instance object) that loads this class must be the same.

Topics: Java jvm