(1) Ali's interviewer asked me , Can you write it yourself String class

answer : may not , because Parent delegation mechanism based on class loading , Will load the parent class , Parent class found conflict String No more loading ;

(2) Can I load the class , Modify the bytecode of the class

answer : sure , use Java Probe technology , You can refer to :Java probe -Java Agent technology - Ali interview questions

Reading table of contents

    What is classloader
    Class loader and class's ” identical “ judge
    Class loader type
  Parents Delegation Model
  Class loading process
  Custom class loader
  JAVA Hot deployment implementation

What is classloader

Responsible for reading Java Byte code , And convert to java.lang.Class An instance of class ;
Class loader and class's ” identical “ judge

Class loaders are used to load classes , It can also be used to determine whether a class Java Uniqueness in virtual machine .

Even the same byte code , The class obtained after being loaded by different class loaders , It's different .

Generally speaking , To determine whether two classes “ identical ”, The premise is that these two classes must be loaded by the same classloader , Otherwise, these two classes do not “ identical ”.
I mean “ identical ”, Including class Class Object's equals() method ,isAssignableFrom() method ,isInstance() method ,instanceof
Keywords, etc .
Class loader type

Start class loader ,Bootstrap ClassLoader, load JACA_HOME\lib, Or by -Xbootclasspath Parameter qualified class
extensions class loader ,Extension ClassLoader, load \lib\ext, Or by java.ext.dirs Class specified by system variable
Application class loader ,Application ClassLoader, load ClassPath Class library in
Custom class loader , By inheritance ClassLoader realization , Generally, loading our custom classes
Parents Delegation Model

Classloader Java Class as other Java Class is the same , Also to be loaded by the classloader ; In addition to the boot class loader , Each class has its parent loader ( Parent-child relationship is composed of ( Not inheritance ) To achieve );

The so-called parent delegation refers to every time a class load request is received , Delegate the request to the parent loader first ( All load requests will eventually be delegated to the top-level Bootstrap
ClassLoader In loader ), If the parent loader cannot complete the load ( No corresponding class found in the loader's search scope ), Subclass tries to load itself .

Benefits of parental delegation

* Avoid multiple loading of the same class ;
* Each loader can only load its own range of classes ; Class loading process
Class loading is divided into three steps : load , connect , initialization ;

As shown below , Is the life cycle of a class from loading to using and unloading , Picture from reference ;


Name a class according to its full limit ( as cn.edu.hdu.test.HelloWorld.class) To read the binary byte stream of this class to JVM inside ;

Converts the static storage structure represented by the byte stream to the runtime data structure of the method area (hotspot Choose to Class Object stored in method area ,Java The virtual machine specification does not explicitly require that it be stored in the method area or heap area )

Convert to a java.lang.Class object ;



The verification stage mainly includes four inspection processes : File format validation , Metadata validation , Bytecode verification and symbol reference verification ;

get ready

Allocate memory space for all static variables in a class , And set an initial value for it ( Since no objects have been generated yet , Instance variables will no longer be within the scope of this operation );


Convert all symbol references in the constant pool to direct references ( Get class or field , Method's pointer or offset in memory , To call the method directly ). This stage can be executed after initialization .


  In the preparation stage of connection , Class variable has been assigned the initial value required by the system once , In the initialization phase , Class variables and other resources are initialized according to the logic written by the programmer himself , Here's an example :
public static int value1 = 5; public static int value2 = 6; static{ value2 =
66; }
In the preparation stage value1 and value2 All equal to 0;

In the initialization phase value1 and value2 Equal to 5 and 66;

All class variable initialization statements and static code blocks are placed in the collector by the front-end compiler at compile time , Store in a special way , This method is <clinit> method , Namely class / Interface initialization method , This method can only be used by JVM call ;
* The order in which the compiler collects is determined by the order in which statements appear in the source file , Only variables defined before a static statement block can be accessed in a static statement block ;
If the superclass has not been initialized , Initialization of superclass is preferred , But in <clinit> Method does not display the calling superclass <clinit> method , from JVM Responsible for ensuring a class's <clinit> Before method execution , Its superclass <clinit> Method has been executed .
JVM You must ensure that a class is in the process of initialization , If multithreading needs to initialize it at the same time , Only one of the threads can be allowed to perform initialization operations on it , The rest of the threads must wait , Only after the active thread finishes initializing the class , Will notify other threads waiting .( So we can use static inner class to realize thread safety )
* If a class does not declare any class variables , There are no static code blocks , Then there can be no classes <clinit> method ;
When to trigger initialization

* When creating a new object instance for a type ( such as new, reflex , serialize )
* When a static method of type is called ( Execution in bytecode invokestatic instructions )
Calling a static field of a type or interface , Or when you assign values to these static fields ( In bytecode , implement getstatic perhaps putstatic instructions ), But with final Except static fields decorated , It is initialized as a compile time constant expression
* call JavaAPI Reflection method in ( For example, call java.lang.Class Method in , perhaps java.lang.reflect Methods of other classes in the package )
* When initializing a derived class of a class (Java When the virtual machine specification explicitly requires a class to be initialized , Its superclass must complete the initialization operation in advance , Interface exception )
* JVM Launch contains main Method's start class time .  
  Custom class loader

  To create a user's own classloader , Just inherit java.lang.ClassLoader class , And then cover its findClass(String
name) Method , That is, how to get the byte stream of the class .

If you want to meet the specification of parent delegation , Then rewrite findClass method ( User defined class loading logic ); To destroy , rewrite loadClass method ( The concrete logic realization of parents' delegation ).

example :
package classloader; import java.io.ByteArrayOutputStream; import java.io.File;
import java.io.FileInputStream; import java.io.IOException; import
java.io.InputStream;class TestClassLoad { @Override public String toString() {
return " Class loaded successfully ."; } } public class PathClassLoader extends ClassLoader { private
String classPath;public PathClassLoader(String classPath) { this.classPath =
classPath; } @Overrideprotected Class<?> findClass(String name) throws
ClassNotFoundException {byte[] classData = getData(name); if (classData == null
) {throw new ClassNotFoundException(); } else { return defineClass(name,
classData, 0, classData.length); } } private byte[] getData(String className) {
String path= classPath + File.separatorChar + className.replace('.',
File.separatorChar) + ".class"; try { InputStream is = new
FileInputStream(path); ByteArrayOutputStream stream= new
ByteArrayOutputStream();byte[] buffer = new byte[2048]; int num = 0; while
((num = is.read(buffer)) != -1) { stream.write(buffer, 0, num); } return
stream.toByteArray(); }catch (IOException e) { e.printStackTrace(); } return
null; } public static void main(String args[]) throws ClassNotFoundException,
InstantiationException, IllegalAccessException { ClassLoader pcl= new
PathClassLoader("D:\\ProgramFiles\\eclipseNew\\workspace\\cp-lib\\bin"); Class c
= pcl.loadClass("classloader.TestClassLoad");// Note include package name
System.out.println(c.newInstance());// Printing class loaded successfully . } }


JAVA Hot deployment implementation

Let's talk about hot deployment first (hotswap), Hot deployment does not restart Java Under the premise of virtual machine , Automatic detection class Changes in documents , Update runtime class
act .Java Class is passed Java Virtual machine loaded , Of a class class The file is being classloader After loading , The corresponding Class
object , You can then create an instance of this class . The default virtual machine behavior only loads classes at startup , If a class needs to be updated later , Simply replace compiled class file ,Java
Virtual machines do not update running class. If you want to achieve hot deployment , The most fundamental way is to modify the source code of the virtual machine , change classloader Load behavior of , Enable virtual monitoring
class Update of documents , Reload class file , It's destructive , For subsequent JVM There's a big hole in the upgrade .

Another friendly way is to create your own classloader To load what needs listening class, In this way, you can control the timing of class loading , For hot deployment . 

  Hot deployment steps :

1, Destroy custom classloader( Loaded by the loader class It will also be uninstalled automatically );

2, to update class

3, Use new ClassLoader Unload class 

JVM In Class Only the following three conditions are met , To be GC recovery , That is to say Class unmounted (unload):

   - All instances of this class have been GC, that is JVM This does not exist in Class Any instance of .
   - Load the ClassLoader Has been GC.
   - Of this type java.lang.Class Object is not referenced anywhere , If you cannot access a method of this class through reflection anywhere


Extend the problem for analysis :

See this topic , A lot of people will think I wrote mine java code , As for class ,JVM Load as you like , Bloggers have long believed the same . With the accumulation of programming experience , Growing sense of the importance of understanding virtual machine related Essentials . Not much gossip , Old rules , Let's start with a code .
public class SSClass { static { System.out.println("SSClass"); } } public class
SuperClassextends SSClass { static { System.out.println("SuperClass init!"); }
public static int value = 123; public SuperClass() { System.out.println("init
SuperClass"); } } public class SubClass extends SuperClass { static {
System.out.println("SubClass init"); } static int a; public SubClass() {
System.out.println("init SubClass"); } } public class NotInitialization { public
static void main(String[] args) { System.out.println(SubClass.value); } }
Operation results : SSClass SuperClass init! 123

The answer is right ?

Some may wonder : Why there is no output SubClass
init.ok~ Explain : For static fields , Only classes that directly define this field will be initialized , Therefore, the static field defined in the parent class is referenced by its subclass , Only the initialization of the parent class will be triggered, not the initialization of the child class .

This involves the loading mechanism of virtual machine classes . If you are interested , You can keep looking .


Class loading process

Class starts from being loaded into virtual machine memory , Until the memory is unloaded , Its entire life cycle includes : load (Loading), verification (Verification), get ready (Preparation), analysis (Resolution), initialization (Initialization), use (Using) And uninstall (Unloading)7 Stages . Preparation , verification , analysis 3 Parts are collectively referred to as connections (Linking). As shown in the figure .

load , verification , get ready , Initialize and uninstall this 5 The sequence of stages is determined , The loading process of a class must start step by step in this order , The parsing phase is not necessarily : It can in some cases start after the initialization phase , This is for support Java Runtime binding for languages ( Also known as dynamic binding or late binding ). The following statements have been made HotSpot As a benchmark .


In the loading phase ( You can refer to java.lang.ClassLoader Of loadClass() method ), The virtual machine needs to complete the following 3 One thing :

* Obtain the binary byte stream defining a class by its fully qualified name ( There's no indication that you're going to Class Get in file , From other channels , for example : network , Dynamic generation , Database, etc );
* Convert the static storage structure represented by this byte stream to the runtime data structure of the method area ;
* Generate in memory a java.lang.Class object , As the access to all kinds of data of this class in method area ;

Load phase and connect phase (Linking) Part of ( For example, some byte code file format verification actions ) It's cross cutting , Loading phase not completed , Connection phase may have started , But these actions are carried out in the loading phase , Content still in the connection phase , The starting time of these two stages is still in a fixed order .


Verification is the first step in the connection phase , The purpose of this phase is to ensure Class The information contained in the byte stream of the file meets the requirements of the current virtual machine , And will not endanger the security of virtual machine itself .
The verification phase will be roughly completed 4 Inspection actions in stages :

File format validation : Verify that the byte stream matches Class Specification of file format ; for example : Whether to use magic 0xCAFEBABE start , Whether the primary and secondary version numbers are within the processing range of the current virtual machine , Whether constants in constant pool have unsupported types .
Metadata validation : Semantic analysis of information described by bytecode ( be careful : contrast javac Semantic analysis in compilation phase ), In order to ensure that the information described in it complies with Java Requirements of language specification ; for example : Does this class have a parent , except java.lang.Object outside .
* Bytecode verification : Through data flow and control flow analysis , Make sure the program semantics are legal , Logical .
* Symbol reference validation : Ensure that parsing actions are performed correctly .

The verification phase is very important , But it's not necessary , It has no effect on the running time of the program , If the referenced class is repeatedly verified , Then consider adopting -Xverifynone Parameter to close most class validation actions , To reduce the load time of virtual machine classes .

get ready

The preparation stage is the stage of formally allocating memory for class variables and setting the initial value of class variables , The memory used by these variables will be allocated in the method area . In this case, only class variables are allocated ( cover static Decorated variable ), Not instance variables , Instance variables are allocated to the heap along with the object when it is instantiated . secondly , The initial value here “ General situation ” Next is the zero value of the data type ,假设一个类变量的定义为:
public static int value=123;


至于“特殊情况”是指:public static final int





public class Test { static { i=0; System.out.println(i);//这句编译器会报错:Cannot
reference a field before it is defined(非法向前应用) } static int i=1; }
public class Test { static { i=0; // System.out.println(i); } static int i=1;
public static void main(String args[]) { System.out.println(i); } }






package jvm.classload; public class DealLoopTest { static class DeadLoopClass {
static { if(true) { System.out.println(Thread.currentThread()+"init
DeadLoopClass"); while(true) { } } } } public static void main(String[] args) {
Runnable script= new Runnable(){ public void run() {
System.out.println(Thread.currentThread()+" start"); DeadLoopClass dlc = new
DeadLoopClass(); System.out.println(Thread.currentThread()+" run over"); } };
Thread thread1= new Thread(script); Thread thread2 = new Thread(script);
thread1.start(); thread2.start(); } }
Thread[Thread-0,5,main] start Thread[Thread-1,5,main] start Thread[Thread
-0,5,main]init DeadLoopClass

static { System.out.println(Thread.currentThread() + "init DeadLoopClass"); try
{ TimeUnit.SECONDS.sleep(10); } catch (InterruptedException e) {
e.printStackTrace(); } }
Thread[Thread-0,5,main] start Thread[Thread-1,5,main] start Thread[Thread-1,5
,main]init DeadLoopClass (之后sleep 10s) Thread[Thread-1,5,main] run over
Thread[Thread-0,5,main] run over


* 使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化.
* 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化.
* 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类.

* 通过数组定义来引用类,不会触发此类的初始化:(SuperClass类已在本文开篇定义)
* public class NotInitialization { public static void main(String[] args) {
SuperClass[] sca= new SuperClass[10]; } }

* 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化: public class
ConstClass {static { System.out.println("ConstClass init!"); } public static
final String HELLOWORLD = "hello world"; } public class NotInitialization {
public static void main(String[] args) {
System.out.println(ConstClass.HELLOWORLD); } }
hello world



参考:类加载机制 <http://www.cnblogs.com/chenpi/p/5393650.html>

参考:Java虚拟机类加载机制 <http://www.cnblogs.com/andy-zhou/p/5324698.html>