Java deep adventure (2) -- loading, linking, and initializing Java classes

Source: Internet
Author: User
Tags apache tomcat websphere application server

In the previous article, we introduced how to manipulate the java byte code, and mentioned how to use the Java class loader to load the modified byte code and execute it on the JVM. Next, I will discuss the loading, linking, and initialization of Java classes. Java byte code is represented by byte arrays (byte []), while Java classes in JVM are represented by Java. Lang. class objects. To use a Java class from byte code to JVM, you must load, link, and initialize the class. In these three steps, developers can directly see the loading of Java classes. By using the Java class loader, a Java class can be dynamically loaded at runtime; the link and initialization are the actions that will occur before the Java class is used. This article describes in detail the process of loading, linking, and initializing Java classes.

Java class loading

Java classes are loaded by the class loader. Generally, classloaders are divided into Bootstrap and user-defined classloaders ). The difference between the two is that the start class loader is implemented by the native JVM code, and the user-defined class loader inherits from the java. Lang. classloader class in Java. In the user-defined class loaders, JVM generally provides some basic implementations. Application developers can also compile their own class loaders as needed. The most common JVM is the system loader, which is used to start loading Java applications. You can use the getsystemclassloader () method of Java. Lang. classloader to obtain the object of the class loader.

The final function required by the class loader is to define a Java class, that is, to convert the java byte code into the java. Lang. Class class object in JVM. However, the process of class loading is not that simple. Java class loaders have two important features: hierarchical structure and proxy mode. The hierarchy structure means that each class loader has a parent class loader, which can be obtained through the getparent () method. The Class Loader organizes the Parent-Child together to form a tree hierarchy. The proxy Mode means that a class loader can complete the definition of Java classes by itself, or delegate to other class loaders. Because of the existence of the proxy mode, the class loader that starts the loading process of a class and the class loader that finally defines this class may not be one. The former is called the initial class loader, and the latter is called the definition class loader. The association between the two is that a Java class definition class loader is the initial class loader of other Java classes imported by this class. For example, if Class A imports Class B through import, Class A defines the class loader to start the loading process of Class B.

Before you try to load a Java class, the Class Loader first proxies to its parent class loader. When the parent class loader cannot be found, it will try to load it by itself. This logic is encapsulated in the loadclass () method of the Java. Lang. classloader class. Generally, the parent class priority policy is good enough. In some cases, you may need to adopt the opposite policy, that is, first try to load by yourself, and then proxy to the parent class loader when it cannot be found. This method is common in Java Web containers and recommended in servlet specifications. For example, Apache Tomcat provides an independent class loader for each web application and uses its own load-first policy. IBM WebSphere Application Server allows web applications to select the policies used by the class loader.

An important purpose of the Class Loader is to create an isolation space for Java classes with the same name in JVM. In JVM, determine whether the two classes are the same, not only according to the binary name of the class, but also according to the definition of the Class Loader of the two classes. Only when the two are identical can the two classes be considered the same. Therefore, even if the same JAVA byte code is defined by two different class loaders, the Java classes are different. If you try to assign values between two classes, a java. Lang. classcastexception will be thrown. This feature creates conditions for coexistence of Java classes with the same name in JVM. In practice, different versions of Java classes with the same name may be required to exist simultaneously in JVM. The class loader can meet this requirement. This technology is widely used in osgi.

Java class Link

The Java class link refers to the process of merging the binary code of the Java class into the running state of the JVM. The class must be loaded successfully before the link is linked. Class links include verification, preparation, parsing, and other steps. Verification is used to ensure that the binary representation of the Java class is fully correct in structure. If an error occurs during verification, a java. Lang. verifyerror error is thrown. The preparation process is to create static fields in the Java class and set the values of these fields to the default values. The preparation process does not execute the code. A Java class contains references to other classes or interfaces, including its parent class, Implemented interfaces, formal parameters of methods, and returned Java classes. The parsing process is to ensure that these referenced classes can be found correctly. The parsing process may cause other Java classes to be loaded.

Different JVM implementations may choose different resolution policies. One way is to recursively resolve all references in the form of links. The other approach may be to resolve the issue only when a formal reference is really needed. That is to say, if a Java class is referenced but not actually used, the class may not be parsed. Consider the following code:

public class LinkTest {      public static void main(String[] args) {             ToBeLinked toBeLinked = null;             System.out.println("Test link.");      }}

The class linktest references the class tobelinked, but does not actually use it. It only declares a variable and does not create an instance of the class or access the static domain. In JDK 6 of Oracle, if you delete the compiled tobelinked JAVA byte code and then run linktest, the program will not throw an error. This is because the tobelinked class is not actually used, and the connection policy adopted by Oracle's JDK 6 makes the tobelinked class not loaded, so it will not find that the tobelinked Java Byte Code does not actually exist. If you change the code to tobelinked = new tobelinked (); and then run the code in the same way, an exception is thrown. This is because the tobelinked class is actually used, and the class needs to be loaded.

Java class initialization

When a Java class is used for the first time, JVM initializes the class. The main operations during initialization are to execute static code blocks and initialize static fields. Before a class is initialized, its direct parent class also needs to be initialized. However, initialization of an interface does not cause initialization of its parent interface. During initialization, static code blocks and static fields are executed sequentially from top to bottom in the source code. Consider the following code:

Public class statictest {public static int x = 10; public static void main (string [] ARGs) {system. out. println (y); // output 60} static {x = 30;} public static int y = x * 2 ;}

In the above Code, static domain initialization and static code block execution are performed from top to bottom during initialization. Therefore, the value of variable X is first initialized to 10, and then assigned to 30. The value of variable Y is initialized to 60.

Java class and interface initialization only occurs at a specific time, including:

  • Create a Java class instance. For example

    MyClass obj = new MyClass()
  • Call a static method in a Java class. For example
    MyClass.sayHello()
  • Assign values to static fields declared in Java classes or interfaces. For example
    MyClass.value = 10
  • Access static fields declared in Java classes or interfaces, and the field is not a constant variable. For example
    int value = MyClass.value
  • Execute the assert statement in the top-level Java class.

Using Java reflection APIs may also cause class and interface initialization. It should be noted that when accessing a static domain in a Java class or interface, only classes or interfaces that actually declare this domain will be initialized. Consider the following code:

Class B {
Static int value = 100;
Static {
System. Out. println ("Class B is initialized."); // output
}
}
Class A extends B {
Static {
System. Out. println ("Class A is initialized."); // No output
}
}
Public class inittest {
Public static void main (string [] ARGs ){
System. Out. println (A. value); // output 100
}
}

In the above Code, the class inittest references the static Domain value declared in Class B through a. value. Because the value is declared in Class B, only Class B is initialized, and Class A is not initialized.

Create your own class loader

During Java application development, you may need to create your own class loader. Typical scenarios include specific JAVA byte code search methods, encryption/decryption of byte code, and isolation of Java classes with the same name. Creating your own classloaders is not complicated. You only need to inherit from the java. Lang. classloader class and override the corresponding method. Many methods are provided in Java. Lang. classloader. The following describes several considerations when creating a Class Loader:

  • Defineclass (): This method is used to complete the conversion from the byte array of JAVA byte code to Java. Lang. Class. This method cannot be overwritten and is generally implemented using native code.
  • Findloadedclass (): This method is used to find the loaded Java class by name. A Class Loader does not repeatedly load classes with the same name.
  • Findclass (): This method is used to search for and load Java classes by name.
  • Loadclass (): This method is used to load the Java class according to the name.
  • Resolveclass (): This method is used to link a Java class.

What is confusing here is the role of the findclass () method and the loadclass () method. As mentioned above, during the Java class link process, the Java class needs to be parsed, And the parsing may cause other Java classes referenced by the current Java class to be loaded. At this time, JVM loads other classes by calling the loadclass () method of the current class definition class loader. The findclass () method is an extension of the Class Loader created by the application. The application's own class loader should overwrite the findclass () method to add custom class loading logic. The default implementation of the loadclass () method calls the findclass () method.

As mentioned above, the proxy mode of the Class Loader uses the parent class priority policy by default. The implementation of this policy is encapsulated in the loadclass () method. If you want to modify this policy, you need to override the loadclass () method.

The following code provides common implementation modes for custom class loading:

Public class myclassloader extends classloader {
Protected class <?> Findclass (string name) throws classnotfoundexception {
Byte [] B = NULL; // find or generate the byte code of the Java class
Return defineclass (name, B, 0, B. Length );
}
}

Reproduced from: http://www.infoq.com/cn/articles/cf-Java-class-loader authorCheng Fu

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.