Creation of Java objects: initialization timing and process of classes

Source: Internet
Author: User
Tags object object reflection serialization stub
Summary:

In Java, an object must be properly initialized before it can be used, as defined by the Java specification. When instantiating an object, the JVM first checks that the correlation type has been loaded and initialized, and if not, the JVM immediately loads and invokes the class constructor to complete the initialization of the class. After the class is initialized or initialized, the class is instantiated based on the specific circumstances. This article attempts to provide a detailed and in-depth description of the JVM's execution of class initialization and instantiation in order to clearly dissect the creation of a Java object from the perspective of a Java virtual machine.

I. Java object creation time

We know that an object must be properly instantiated before it can be used. In Java code, there are many behaviors that can cause an object to be created, and the most intuitive is to use the New keyword to invoke the constructor of a class to explicitly create an object, which is known in the Java specification as an object creation that is caused by an execution class instance creation expression . In addition, we can also use the reflection mechanism (the class's Newinstance method, the Newinstance method using the constructor class), the use of the Clone method, the use of deserialization, and other ways to create the object. The following is a brief description of the author:

1). Create an object using the New keyword

This is our most common and simplest way to create objects, and in this way we can invoke arbitrary constructors (without arguments and arguments) to create objects. Like what:

Student Student = new Student ();

2). Using the class Newinstance method (reflection mechanism)

We can also use the Newinstance method of the class class to create an object through the reflection mechanism of Java, in fact, the Newinstance method calls the parameterless constructor to create the object, such as:

Student Student2 = (Student) class.forname ("Student class fully qualified name"). newinstance (); Or: Student stu = Student.class.newInstance ();

3). Using the Newinstance method of the constructor class (reflection mechanism)

There is also a newinstance method in the Java.lang.relect.Constructor class that can create objects, much like the Newinstance method in class classes, but in contrast, the Newinstance method of the constructor class is more powerful, We can call arguments and private constructors through this newinstance method, such as:

public class Student {   private int id;   Public Student (Integer ID) {       this.id = ID;   }   public static void Main (string[] args) throws Exception {       constructor<student> Constructor = Student.class               . GetConstructor (integer.class);       Student stu3 = constructor.newinstance (123);}   }

These two ways of using the Newinstance method create objects using the reflection mechanism of Java, in fact the Newinstance method of class is also constructor Newinstance method.

4). Create an object using the Clone method

Whenever we invoke the Clone method of an object, the JVM will help us create a new, identical object, and it is particularly necessary to note that no constructors are called in the process of creating an object with the Clone method. Simply put, to use the Clone method, we must first implement the Cloneable interface and implement its definition of the Clone method, which is also the application of prototype mode. Like what:

public class Student implements cloneable{   private int id;   Public Student (Integer ID) {       this.id = ID;   }   @Override   protected Object Clone () throws Clonenotsupportedexception {       //TODO auto-generated method stub       return Super.clone ();   }   public static void Main (string[] args) throws Exception {       constructor<student> Constructor = student.class< C11/>.getconstructor (integer.class);       Student stu3 = constructor.newinstance (123);       Student Stu4 = (Student) stu3.clone ();}   }

5). Create an object using the (reverse) serialization mechanism

When we deserialize an object, the JVM creates a separate object for us, during which the JVM does not invoke any constructors. In order to deserialize an object, we need to have our class implement the Serializable interface, for example:

public class Student implements Cloneable, Serializable {   private int id;   Public Student (Integer ID) {       this.id = ID;   }   @Override public   String toString () {       return "Student [id=" + ID + "]";   }   public static void Main (string[] args) throws Exception {       constructor<student> Constructor = student.class
  .getconstructor (integer.class);       Student stu3 = constructor.newinstance (123);       Write Object       objectoutputstream output = new ObjectOutputStream (               new FileOutputStream ("Student.bin"));       Output.writeobject (STU3);       Output.close ();       Read Object       objectinputstream input = new ObjectInputStream (New FileInputStream (               "Student.bin"));       Student Stu5 = (Student) input.readobject ();       System.out.println (STU5);   }}

6). Full instance

public class Student implements Cloneable, Serializable {private int id;   Public Student () {} public Student (Integer id) {this.id = ID;       } @Override protected Object clone () throws Clonenotsupportedexception {//TODO auto-generated method stub   return Super.clone ();   } @Override Public String toString () {return "Student [id=" + ID + "]";       public static void Main (string[] args) throws Exception {System.out.println ("create object using the New keyword:");       Student stu1 = new Student (123);       System.out.println (STU1);       System.out.println ("\ n---------------------------\ n");       System.out.println ("Using the class Newinstance method to create an object:");    Student STU2 = Student.class.newInstance ();       The corresponding class must have an parameterless construction method, and only this one is created System.out.println (STU2);       System.out.println ("\ n---------------------------\ n");       System.out.println ("Create object using the Newinstance method of the constructor class:"); Constructor<student> Constructor = Student.class. getconsTructor (Integer.class);          Call the parameter construction method Student STU3 = Constructor.newinstance (123);       System.out.println (STU3);       System.out.println ("\ n---------------------------\ n");       System.out.println ("Create object using Clone method:");       Student Stu4 = (Student) stu3.clone ();       System.out.println (STU4);       System.out.println ("\ n---------------------------\ n");       System.out.println ("Use (reverse) serialization mechanism to create objects:");       Write Object ObjectOutputStream output = new ObjectOutputStream (New FileOutputStream ("Student.bin"));       Output.writeobject (STU4);       Output.close ();       Read object ObjectInputStream input = new ObjectInputStream (New FileInputStream ("Student.bin"));       Student Stu5 = (Student) input.readobject ();   System.out.println (STU5); }}/* Output: Create an object using the New keyword: Student [id=123]---------------------------use the class's Newinstance method to create a Elephant: Student [id=0]---------------------------using Newin of constructor classStance method Creation object: Student [id=123]---------------------------object creation using the Clone method: Student [id=123]- --------------------------create an object using the (inverse) serialization mechanism: Student [id=123]*///:~

From the Java Virtual machine level, in addition to using the New keyword to create objects, all other ways to create objects directly by converting to invokevirtual directives.

Two. Java Object creation Process

When an object is created, the virtual machine allocates memory for it to hold the object's own instance variables and their instance variables inherited from the parent class (even if the instance variables inherited from the superclass may be hidden and allocated space). These instance variables are also assigned default values (0 values) while allocating memory for these instance variables. after the memory allocation is complete, the Java Virtual machine begins to initialize the newly created object according to the will of the program ape. During the initialization of Java objects, there are mainly three kinds of structures that perform object initialization, namely instance variable initialization , instance code block initialization and constructor initialization .

1. Initialization of instance variables and instance code block initialization

While defining (declaring) instance variables, we can also assign values directly to instance variables or use instance code blocks to assign them. If we initialize the instance variables in either of these ways, they will complete these initialization operations before the constructor executes. In fact, if we assign a value directly to an instance variable or use an instance code block, the compiler puts the code in the class's constructor, and the code is placed after the call statement to the superclass constructor (remember?). Java requires that the first statement of the constructor must be the calling statement of the superclass constructor, before the code of the constructor itself. For example:

public class Instancevariableinitializer {     private int i = 1;     private int J = i + 1;     public Instancevariableinitializer (int var) {       System.out.println (i);       System.out.println (j);       This.i = var;       System.out.println (i);       System.out.println (j);   }   {               //instance code block       J + = 3;    }   public static void Main (string[] args) {       new Instancevariableinitializer (8);}   } /* Output:            1           5           8           5*///:~

The above example just confirms the above conclusion. It is important to note that Java executes the code in the instance variable initializer and the instance initializer in a programmatic order, and does not allow the pre-ordered instance code block to initialize the instance variables defined later, such as:

public class Instanceinitializer {     {         j = i;     }     private int i = 1;     private int J;  }  public class Instanceinitializer {     private int j = i;     private int i = 1;  }

The code above is not compiled, and the compiler complains that we have used an undefined variable. This is done to ensure that a variable has been properly initialized before it is used. But we still have a way to circumvent such checks, such as:

public class Instanceinitializer {     private int j = Geti ();     private int i = 1;     Public Instanceinitializer () {         i = 2;     }     private int Geti () {         return i;     }     public static void Main (string[] args) {         Instanceinitializer II = new Instanceinitializer ();         System.out.println (II.J);     }  }

If we execute the above code, we will find that the result of printing is 0. So we can be sure that the variable j is given the default value of I, 0, which occurs before the instance variable i is initialized and before the constructor call.

2. Constructor initialization

We can tell from the above that instance variable initialization and instance code block initialization always occur before constructor initialization, so we'll focus on the constructor initialization process. As we all know, every object in Java has at least one constructor, and if we don't explicitly define a constructor, it will have a default parameterless constructor. In the compiled bytecode, these constructors are named as the <init> () method, and the parameter list is the same as the parameter list for constructors written in the Java language.

We know thatJava requires that its superclass be instantiated before the class is instantiated to guarantee the integrity of the created instance. In fact, this is guaranteed in the constructor: Java enforces the Object object (object is the top-level object of Java, no superclass) except that the first statement must be the calling statement of the superclass constructor or other constructor defined in the class. If we have neither called other constructors nor explicitly called the superclass constructors, then the compiler will automatically generate a call to the superclass constructor for us, such as:

public class Constructorexample {  }

For the classes defined in the above code, we observe the compiled bytecode, and we will find that the compiler generates a constructor for us, as follows:

Aload_0  invokespecial   #8;//method java/lang/object. " <init> ":() V  return

The second line of the above code is the instruction that invokes the default constructor of the object class. That is, if we explicitly call the constructor of a superclass, the call must be placed at the top of all code in the constructor, that is, the first instruction of the constructor. Because of this, Java makes it possible for an object to initialize all of its superclass before it is initialized, and to ensure that a complete object is created.

In particular, if we call another constructor in one constructor, as shown below,

public class Constructorexample {     private int i;     Constructorexample () {This         (1);         ....     }     constructorexample (int i) {         ....         this.i = i;         ....     }  }

In this case, Java only allows the constructor of the superclass to be called within constructorexample (int i), which means that the code compilation for the following two scenarios is not possible:

public class Constructorexample {     private int i;     Constructorexample () {         super ();         This (1);  Error:constructor call must is the first statement in a Constructor       ....     }     constructorexample (int i) {         ....         this.i = i;         ....     }  }

Or

public class Constructorexample {     private int i;     Constructorexample () {This         (1);         Super ();  Error:constructor call must is the first statement in a Constructor       ....     }     constructorexample (int i) {         this.i = i;     }  }

Java makes this restriction on constructors to ensure that instances of a class are properly initialized before they are used.

3. Summary

In summary, the process of instantiating an object of a class is a typical recursive process , as shown in. Further, when instantiating an object of a class, the process is as follows:

Before you are ready to instantiate an object of a class, you first prepare to instantiate the parent class of the class, and if the parent class of the class has a parent class, you are ready to instantiate the parent class of the class, recursively until it is recursive to the object class. At this point, the object class is instantiated first, and then the following categories are instantiated, until the target class is instantiated. Specifically, each class is instantiated in the following order: instance variable initialization and instance code block initialization, followed by constructor initialization. That is, the compiler puts the instance variable initialization and the instance code block initialization related code in the constructor of the class, and the code is placed before the code of the constructor itself after the call statement to the superclass constructor.

4, instance variable initialization, instance code block initialization, and constructor initialization synthetic instance

Parent class class Foo {   int i = 1;   Foo () {       System.out.println (i);             -----------(1)       int x = GetValue ();       SYSTEM.OUT.PRINTLN (x);             -----------(2)   }   {       i = 2;   }   protected int GetValue () {       return i;   }} Subclass Class Bar extends Foo {   int j = 1;   Bar () {       j = 2;   }   {       j = 3;   }   @Override   protected int getValue () {       return J;   }} public class Constructorexample {public   static void Main (String ... args) {       bar bar = new Bar ();       System.out.println (Bar.getvalue ());             -----------(3)   }}/* Output:            2           0           2*///:~

According to the class instantiation procedure described above, we can change the constructor of the Foo class and the constructor of the bar class to the following form:

Equivalent transformation of the Foo class constructor:   foo () {       i = 1;       i = 2;       System.out.println (i);       int x = GetValue ();       SYSTEM.OUT.PRINTLN (x);   }
The equivalent transformation of Bar class constructor   Bar () {       Foo ();       j = 1;       j = 3;       j = 2   }

This procedure is much more beautiful, we can see the output of the program at a glance. The Foo class constructor is called first when an instance of the bar class is constructed by using the bar class's construction method, so the output at (1) is 2, which can be seen directly from the equivalent transformation of the Foo class constructor. (2) The output is 0, why? Because the bar overloads the GetValue method in Foo during the execution of the constructor of Foo, it is possible to know from the Java polymorphism that the GetValue method it calls is the GetValue method that is overloaded by bar. However, since the bar's constructor has not yet been executed, the value of J at this point is still the default value of 0, so (2) the output is 0. Finally, when executing the code at (3), because the bar object has been created, the value of J is then accessed at this point, and then the value 2 is initialized, which can be seen directly from the equivalent transformation of the bar class constructor.

Three. Initialization timing and process of classes

Simply put, during class loading, the prep phase is a stage that formally allocates memory for a class variable (static member variable) and sets the initial value of the class variable (0 value), while the initialization phase is the process of actually starting to execute the Java program code (bytecode) defined in the class and initializing the class variable as the program ape intends. More directly, the initialization phase is the process of executing the class constructor <clinit> () method. The <clinit> () method is generated by the combination of assignment actions for all class variables in the class and static code block static{}, where the compiler collects the order determined by the order in which the statements appear in the source file.

  The class constructor <clinit> () differs from the instance constructor <init> (), which does not require the programmer to make an explicit call, and the virtual opportunity guarantees that the class constructs of the parent class before the subclass class constructor <clinit> () is executed < Clinit> () execution is complete. because the constructor <clinit> () of the parent class executes first, it means that the initialization of the static code block/static variable defined in the parent class takes precedence over the initialization of the static code block/static variable of the subclass. In particular, class constructors <clinit> () are not required for classes or interfaces, and if there is no static code block in a class and no assignment of class variables, the compiler can not produce class constructors <clinit> () for this class. Also, under the same ClassLoader, a class is initialized only once, but a class can instantiate an object arbitrarily. That is, in the life cycle of a class, the class constructor <clinit> () is called at most once by the virtual machine, and the instance constructor <init> () is called multiple times by the virtual machine, as long as the programmer is still creating the object.

Note that the so-called instance constructor <init> () refers to the assignment action of all instance variables in the collection class, the combination of instance code blocks and constructor functions, similar to the equivalent transformations made above for the constructors of the Foo class and the constructors of the bar class.

Four. Summary

1. How many times will an instance variable be assigned during object initialization?

We know that when the JVM allocates memory for an object, it assigns the default value to each instance variable, which is the first time the instance variable is assigned, and there is no way to avoid the assignment process. If we assign a value to an instance variable x at the same time, the instance variable is assigned the second time. If we initialize the variable x in the instance code block, then this instance variable is assigned the third time. If we initialize the variable x in the constructor, then the variable x is assigned the fourth time. That is, during the initialization of an object in Java, an instance variable can be initialized up to 4 times.

2. What are the similarities and differences between the class initialization process and the class instantiation process?

Class initialization is the process by which class variables are assigned to the intent of the program ape during the initialization phase of the class loading process, whereas the instantiation of a class refers to the process of creating an object after the class is fully loaded into memory.

3, if a class has not yet been loaded into memory, then when creating an instance of the class, what is the specific process?

We know that to create an instance of a class, you must first load the class into memory and initialize it, that is, the class initialization operation takes place before the class instantiation operation, but it does not mean that the class instantiation operation can only be done after the class initialization operation has ended.

public class Statictest {public   static void Main (string[] args) {       staticfunction ();   }   static Statictest st = new Statictest ();   static {   //code block       System.out.println ("1");   }   {       //instance code block       System.out.println ("2");   }   Statictest () {    //instance constructor       System.out.println ("3");       System.out.println ("a=" + A + ", b=" + b);   }   public static void Staticfunction () {   //static method       System.out.println ("4");   }   int a =;    Instance variable   static int b =;     Static variable}/* Output:        2       3       a=110,b=0       1       4*///:~

In general, the general procedure for class instantiation is: class constructor for the parent class <clinit> () subclass class Constructors <clinit> (), member variables of the parent class, and the constructor for the parent class, the instance code block- Constructors for subclass > member variables and instance code blocks, subclasses.

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.