Java Foundation (class loading and ClassLoader understanding)

When a program actively uses a class, if the class has not been loaded into memory, the system will initialize the class through the following three steps

load

Load the bytecode content of the class file into memory, convert these static data into the runtime data structure of the method area, and then generate a java.lang.Class object representing this class as the access entry for the class data in the method area (i.e. reference address). All class data that needs to be accessed and used can only be accessed through this class object. This loading process requires the participation of class loader.

link

The process of merging the binary code of a Java class into the running state of the JVM.

  1. Verification: ensure that the loaded class information conforms to the JVM specification. For example, starting with cafe, there is no security problem
  2. Preparation: the stage of formally allocating memory for class variables (static) and setting the default initial value of class variables. These memory will be allocated in the method area.
  3. Resolution: the process of replacing the symbolic reference (constant name) in the virtual machine constant pool with a direct reference (address).

initialization:

  1. The process of executing the class constructor () method. The class constructor () method is generated by the combination of the assignment action of all class variables in the class automatically collected at compile time and the statements in the static code block. (the class constructor constructs class information, not the constructor of the class object).
  2. When initializing a class, if it is found that its parent class has not been initialized, the initialization of its parent class needs to be triggered first.
  3. Virtual chance ensures that the () methods of a class are locked and synchronized correctly in a multithreaded environment.

Functions of class loader:

  1. The function of class loading: load the bytecode content of the class file into memory, convert these static data into the runtime data structure of the method area, and then generate a java.lang.Class object representing this class in the heap as the access entry to the class data in the method area.
  2. Class caching: the standard JavaSE class loader can find classes as required, but once a class is loaded into the class loader, it will remain loaded (cached) for a period of time. However, the JVM garbage collection mechanism can recycle these class objects.

Class loader is used to load classes into memory. The JVM specification defines class loaders of the following types.

ClassLoaderTest.java

package com.klvchen.java;

import org.junit.Test;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Properties;

public class ClassLoaderTest {

    @Test
    public void test1(){
        // For custom classes,Load using system class loader
        ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        System.out.println(classLoader);
        //Calling the system class loader getParent():Get extension class loader
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);
        //Calling the extension class loader getParent():Unable to get boot class loader
        //The bootstrap class loader is mainly responsible for the class library and cannot load custom classes.
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);

        ClassLoader classLoader3 = String.class.getClassLoader();
        System.out.println(classLoader3);

    }


    /*
      Properties: Used to read configuration files.
     */
    @Test
    public void test2() throws Exception {
        Properties pros = new Properties();
        //At this time, the file defaults to the current file module lower
        //How to read the configuration file:
        FileInputStream fis = new FileInputStream("src\\jdbc1.properties");
        pros.load(fis);

        //How to read the configuration file: use CLassLoader
        //The configuration file is recognized by default as: current module Yes src lower
        //ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
        //InputStream is = classLoader.getResourceAsStream("jdbc1.properties");
        //pros.load(is);

        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        System.out.println("user = " + user + ",password = " + password);
    }
}

jdbc1.properties

user=wasp
password=abc123456

jdbc.properties

user=Wu Fei
password=abc123

NewInstanceTest.java

package com.klvchen.java;

import org.junit.Test;

import java.util.Random;

public class NewInstanceTest {

    @Test
    public void test1() throws Exception {
        Class<Person> clazz = Person.class;

        /*
        newInstance():Call this method to create the object of the corresponding runtime class. Internally, call the constructor of the null parameter of the runtime class

        To create the object of the runtime class normally with this method, you need to:
        1.The runtime class must provide a constructor with null parameters
        2.The constructor of null parameter has sufficient access rights. Usually, it is set to public

        A public null parameter constructor is required in the java bean. Reason:
        1.It is convenient to create objects of runtime classes through reflection
        2.When a subclass inherits this runtime class, it is guaranteed that the parent class has this constructor when super() is called by default

         */
        Person obj = clazz.newInstance();
        System.out.println(obj);
    }

    //Dynamics of reflection
    @Test
    public void test2(){
        int num = new Random().nextInt(3);//0,1,2
        String classPath = "";
        switch (num) {
            case 0:
                classPath = "java.util.Date";
                break;
            case 1:
                classPath = "java.lang.Object";
                break;
            case 2:
                classPath = "com.klvchen.java.Person";
                break;
        }

        try {
            Object obj = getInstance(classPath);
            System.out.println(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /*
    Creates an object of the specified class.
    classPath:Specifies the full class name of the class
     */
    public Object getInstance(String classPath) throws Exception {
        Class clazz = Class.forName(classPath);
        return clazz.newInstance();
    }
}

Person.java

package com.klvchen.java;

public class Person {

    private String name;
    public int age;

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person() {
        System.out.println("Person()");
    }

    private Person(String name) {
        this.name = name;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void show() {
        System.out.println("Hello, I'm alone");
    }

    public String showNation(String nation) {
        System.out.println("My nationality is: " + nation);
        return nation;
    }
}

ReflectionTest.java

package com.klvchen.java;

import org.junit.Test;

import java.lang.annotation.ElementType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectionTest {

    // Before reflection, for Person Operation of
    @Test
    public void test1(){
        //1.establish Person Object of class
        Person p1 = new Person("Tom", 12);

        //2.Through the object, call its internal properties and methods
        p1.age = 10;
        System.out.println(p1.toString());

        p1.show();

        //stay Person Class, cannot be passed Person Class calls its internal private structure.
        //such as: name . showNation()And private constructors

    }

    //After reflection, for Person Operation of
    @Test
    public void test2() throws Exception {

        Class clazz = Person.class;
        //1.By reflection,establish Person Object of class
        Constructor cons = clazz.getConstructor(String.class, int.class);
        Object obj = cons.newInstance("Tom", 12);
        Person p = (Person) obj;
        System.out.println(p.toString());

        //2.Through reflection, call the properties and methods specified by the object
        //Call properties
        Field age = clazz.getDeclaredField("age");
        age.set(p, 10);
        System.out.println(p.toString());

        //Call method
        Method show = clazz.getDeclaredMethod("show");
        show.invoke(p);

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

        //Through reflection, you can call Person Class. For example:Private constructors, methods, properties
        Constructor cons1 = clazz.getDeclaredConstructor(String.class);
        cons1.setAccessible(true);
        Person p1 = (Person) cons1.newInstance("Jerry");
        System.out.println(p1);

        //Call private properties
        Field name = clazz.getDeclaredField("name");
        name.setAccessible(true);
        name.set(p1, "HanMeimei");
        System.out.println(p1);

        //Call private methods
        Method showNation = clazz.getDeclaredMethod("showNation", String.class);
        showNation.setAccessible(true);
        String nation = (String) showNation.invoke(p1, "China");//amount to String nation = p1.showNation("China")
        System.out.println(nation);

    }

    /*
    Understanding of java.lang.Class class
    1.Class loading process:
      After the program passes the javac.exe command, it will generate one or more bytecode files (. End of class).
      Then we use the java.exe command to interpret and run a bytecode file, which is equivalent to loading a bytecode file into memory.
      This process is called Class loading. The Class loaded into memory is called the runtime Class, which is used as an instance of Class.
    2.In other words, an instance of Class corresponds to a runtime Class.
    3.The runtime class loaded into memory will be cached for a certain time. Within this time, we can obtain this runtime class in different ways.
     */

    // obtain Class How instances of
    @Test
    public void test3() throws ClassNotFoundException {
        //Mode 1: Call the properties of the runtime class:.class
        Class clazz1 = Person.class;
        System.out.println(clazz1);
        //Mode II: Objects through runtime classes, call getclass()
        Person p1 = new Person();
        Class clazz2 = p1.getClass();
        System.out.println(clazz2);

        //Mode III: call Class Static method of:forName(String classPath)
        Class clazz3 = Class.forName("com.klvchen.java.Person");
        //Class clazz3 = Class.forName("java.lang.String");
        System.out.println(clazz3);

        System.out.println(clazz1 == clazz2);
        System.out.println(clazz1 == clazz3);

        //Mode 4:Use class loader: ClassLoader
        ClassLoader classLoader = ReflectionTest.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("com.klvchen.java.Person");
        System.out.println(clazz4);

        System.out.println(clazz1 == clazz4);

    }

    @Test
    public void test4(){
        Class c1 = Object.class;
        Class c2 = Comparable.class;
        Class c3 = String[].class;
        Class c4 = int[][].class;
        Class c5 = ElementType.class;
        Class c6 = Override.class;
        Class c7 = int.class;
        Class c8 = void.class;
        Class c9 = Class.class;

        int[] a = new int[10];
        int[] b = new int[100];
        Class c10 = a.getClass();
        Class c11 = b.getClass();
        //As long as the element type is the same as the dimension, it is the same class
        System.out.println(c10 == c11);
    }
}

 

Tags: Java

Posted on Mon, 29 Nov 2021 08:15:14 -0500 by gotDNS