As we all know, programming languages are divided into compiled and interpreted languages from the execution of programs.

So is Java an interpreted or compiled language?

Java is a compiled language

Remember when we first learned Java, we used the javac command to compile Java code to generate.class bytecode files. This is a necessary step, as.java bytecode files cannot run without compilation.

Java is an interpreted language

Above we compiled Java files into.class files using the javac command, which is Java’s own special type of file that runs on the virtual machine (JVM). The Java virtual machine interprets. Class files line by line and translates them into instructions (sequences of zeros and ones) that can be read by the corresponding computer, so Java is said to be an interpreted language.

Having said that, we have to talk about Java cross-platform. Because. Class must run on a JVM, Java is cross-platform. Different operating systems have different JVMS, but. Class can be interpreted and run on them. As an example, the JVM is just like a translator, when someone important speak Chinese (Java file), will be the Java compiler to compile into English (. The class bytecode file), when this English document is transmitted to the various countries, and by the local translators (JVM) translated into the local language (machine language), For local people to learn.

So the JVM acts as a local translator, translating.class bytecode files into sequences of zeros and ones that can be given to the computer to recognize execution. This does the trick of compiling once and running everywhere.

In summary:

  • The JVM is like the operating system for Java programsOperating SystemThe files that can be executed are. Class bytecode files.
  • The JVM masks differences between operating systems, allowing.class files compiled once to run on different JVMS on different operating systems.

So how do.class files get executed by the JVM? Let me tell you all about it.

What is class loading

Let’s start with a picture:

From the above we can see that.class bytecode files are loaded into the JVM by the class loader. This article focuses on that part — class loading

In general, the loading of a class is simply a matter of reading the binary numbers from the.class bytecode file into memory and placing them in the data area method, and then creating a Java.lang. class object in the heap that encapsulates the data structure in the method area.

So, when does the classloader area start loading classes?

Instead of waiting until a class is ready to be used, the JVM allows the classloader to load a class when it expects it to be used. If an error or error occurs in the.class file during preloading, The class loader does not report a LinkageError until the program first actively uses the class, but does not report a LinkageError if the class has never been used.

Second, the process of class loading

From the moment a type is loaded into the VM memory to the moment it is uninstalled, its whole life cycle goes through seven stages: loading, verifying, preparing, parsing, initializing, using, and uninstalling. The three parts of verifying, preparing, and parsing are collectively called connections. The sequence of these seven stages is shown below.

The five phases of load, validation, preparation, initialization, and unload are in a definite order. The loading of a class must begin in this order, while the parsing phase may not. It can be started after the initialization phase in some cases to support dynamic binding in the Java language.

Note: The reason to say “start” rather than “proceed” or “finish” is that these phases are often intermingled with each other, invoking and activating one phase during the execution of another.

1, load,

The “load” phase is one of the “class loading” phases. During the load phase, the Java VIRTUAL machine needs to do three things:

  1. Get the binary byte stream that defines a class by its fully qualified name;
  2. Convert the static storage structure represented by this byte stream to the runtime data structure of the method area;
  3. Generate a java.lang.Class object in memory that represents the Class and acts as an access point for the Class’s various data in the method area.

Note: The Class structure is created for the loaded Class. Before JDK1.8, it is stored in the method area, and after JDK1.8, it is stored in the meta-space (more on runtime memory partitioning). The third Class instance object is created in the heap, and each Class corresponds to an object of type Class. The interface provided by the Class Class can be used to obtain the specific data structure in the.class file associated with the target Class.

We see that the first point, “get the binary byte stream by the fully qualified name of a class,” does not indicate where or how it must be obtained. This creates an open arena for Java virtual machine users during the loading phase. We can get it from the following:

(1) Local disk

(2) Load the. Class file (Applet) online.

(3) From the database

(4) Compressed files (ZAR, JAR, etc.)

(5) Generated from other files (JSP application)

(6) Dynamic proxy……

2, validation,

This is the first step in the connection phase. The purpose of verification is to ensure that the byte stream in the Class file complies with all the constraints of the Java Virtual Machine Specification. In other words, to check whether the byte stream in the Class file will endanger the virtual machine itself.

The validation phase roughly completes four stages of checking actions: file format validation, metadata validation, bytecode validation, and symbol reference validation.

The validation phase is an important but unnecessary phase for the entire class loading mechanism. If our code ensures that there are no problems, then there is no need to validate it because it takes time. Of course we can use -xverfity: None to turn off most validation.

3, preparation,

The preparation phase is the phase that sets the initial values for class variable allocation, that is, the memory space used by these variables is allocated in the method area.

Note the concept of initial values, such as a class variable defined as: public static int v = 8080

The put static instruction that assigns v to 8080 is stored in the class constructor method after the program is compiled, so assigning v to 8080 will not be performed until the initialization phase.

But note that if the declaration is: public static final int v = 8080;

The ConstantValue attribute is generated for V during compilation, and the virtual machine assigns v a value of 8080 based on the ConstantValue attribute during preparation.

At compile time Javac will generate a ConstantValue attribute for static and final constants. In preparation for class loading, the virtual machine will set the ConstantValue for the constant according to the ConstantValue. Then the value of a becomes 100 during the preparation phase), which is what the ConstantValue property does during the preparation phase of the class loading process

4, parsing,

The parsing phase is the process by which the virtual machine replaces symbolic references in the constant pool with direct references. Symbolic references are in the class file:

CONSTANT_Class_info, CONSTANT_Field_info, CONSTANT_Method_info, etc.

Symbolic reference

Symbolic references are independent of the layout implemented by the virtual machine, and the target of the reference does not have to have been loaded into memory. The memory layout of various virtual machine implementations can vary, but the symbolic references they accept must be consistent, because the literal form of symbolic references is explicitly defined in the Class file format of the Java Virtual Machine specification. Just like in a class, the teacher can refer to you as Joe, or you can refer to you as your student number, but in any case this is just a code name (symbol), the code name refers to you (symbol reference).

Direct reference

A direct reference can be a pointer to a target, a relative offset, or a handle that can be indirectly located to the target. If there is a direct reference, the target of the reference must already exist in memory.

5. Initialization

The last step in class loading, where the Java virtual machine actually executes the Java program code written in the class, handing control to the application. The initialization phase is the process of executing the class constructor methods.

Class variables have been assigned once in the preparation phase. During the initialization phase, programmers can assign values according to their own needs.

The above words are too abstract, let me give you a simple example.

A a = new A("CS-Review");
Copy the code

The above code uses the new keyword to instantiate A string object, so the class A constructor is called to instantiate A.

Class loaders

There are three important classloaders built into the JVM.

  1. BootstrapClassLoader: the top-level loading class, implemented by C++, is responsible for loading%JAVA_HOME%/libJar packages or classes in the directory.
  2. ExtensionClassLoader: Is responsible for loading directories%JRE_HOME%/lib/extJar packages or classes in the directory.
  3. AppClassLoader: a user-facing loader that loads all jar packages and classes in the current application classpath.

We users can also customize class loaders.

As you can see, except for BootstrapClassLoader, all class loaders are implemented in Java and fully inherit java.lang.classLoader. So, we need to define our own ClassLoader, which needs to inherit from ClassLoader.

public class ClassloaderTest {
    public static void main(String[] args) {
        ClassLoader loader = ClassloaderTest.class.getClassLoader();
        System.out.println(loader);  // App
        System.out.println(loader.getParent());  //ExtSystem.out.println(loader.getParent().getParent()); }}Copy the code

Output:

The Bootstrap Loader is implemented in C language. There is no definite way to return the parent Loader, so null is returned.

Here are a few small questions

So why custom class loaders?

  • Isolated loading classes (because the middleware will have its own defined JAR, there will be jar packages or classes with the same name and path in the same project, there will be conflicts, need to be isolated loading)

  • Modify the way classes are loaded

  • Extended load source

  • Prevent source code leakage

What does a class loader do?

Its purpose is to complete the load phase of the task. (Load the class file bytecode into memory, convert the static storage structure into a method area runtime data structure, and then generate a java.lang.class object representing the class in the heap as an entry point to that data structure.)

How to obtain a ClassLoader

Class.forName(“…” .getClassLoader() gets the ClassLoader for the current class

Thread.currentthread ().getcontextclassloader () gets the ClassLoader for the currentThread context

This getSystemClassLoader () for this system

DriverManager. GetCallerClassLoader () to obtain the caller of this

4. Parent delegation mechanism

Each class has a corresponding class loader. The JVM loads class files on demand. Classloaders in the system use parental delegation by default when working together.

During class loading, the system first checks whether the current class has been loaded by the current class loader. The loaded class is returned directly. Otherwise, the system tries to load the class.

When loading, the request is first delegated to the parent class loaderloadClass()Because all requests will eventually reach the startup class loaderBootstrapClassLoaderIn the.

When the parent class is ready to load, it returns successfully. When the parent class loader can’t handle it, you handle it yourself.

One advantage of using parental delegation is that, for example, loading the java.lang.Object class in the rt.jar package, whichever loader loads the class ends up delegating to the top bootstrap class loader, thus ensuring that different classloaders will end up with the same Object.

For example, we customize the java.lang.String class, and when the class is first used actively, the JVM starts the class loader to try to load it, based on the parent delegate mechanism. Instead, it finds the java.lang.String class in the Rt.jar package and loads it into memory (it doesn’t load our custom String class). If we write main in the String class, we will report that main does not have an error.

The String class in the rt.jar package is loaded to ensure the protection of the Java core source code, which is the sandbox security mechanism.

Advantages of parental delegation:

  • Avoid reloading classes
  • Protect program security and prevent the core API from being tampered with
  • Custom classes: java.lang.ShkStart (error, prevents creation of java.lang classes) receives a SecurityException even if a custom class loader is used to force loading.

END

Crustily skin of head finally finished writing, this article is really hard to write, write out the meaning of the distorted the original intention, so through a large amount of data and blogs, and finally finished, although for a long time before already learned, but after this article writing, deepened the understanding of the Java class loading mechanism, make their knowledge of this type of resist no longer.

The resources

  • Understanding the Java Virtual Machine in Depth: Advanced JVM Features and Best Practices (3rd edition) ———— Zhiming Zhou
  • zhuanlan.zhihu.com/p/73078336