In the previous article, “A Complete Overview of Java reflection”, we learned the basics of Java reflection. If you are paying attention, you may have noticed that there are three ways to get Class objects.

If Java reflection is involved in your interview, your chances of getting that interview question increase dramatically.

What is the difference between the following three ways to get a Class object?

1, new Object().getClass 2, Object.class 3, class.forname (” java.util.string “)

This article will take you through the differences between the three methods of obtaining Class objects. The example is based on JDK8.

Example Demonstrate scenario 1

For better demonstration, let’s start by creating an object, Person, with some static methods defined inside.

Public class Person {static {system.out.println ("Person: static code block "); } {system.out.println ("Person: dynamic code block "); } public Person(){system.out.println ("Person: constructor "); }}Copy the code

The Person object defines static code blocks, dynamic code blocks, and constructors.

For the above example, we built three unit test scenarios, corresponding to the following code:

public class GetClassTest { @Test public void test1(){ Class<? > clz = Person.class; } @Test public void test2() throws ClassNotFoundException { Class<? > clz = Class.forName("com.choupangxia.reflect.Person"); } @Test public void test3() { Class<? > clz = new Person().getClass(); }}Copy the code

Running three separate unit tests found that the first unit test didn’t print anything; The second unit test prints the contents of “static methods”; The third unit test prints out the whole thing:

Person: static code block Person: dynamic code block Person: constructorCopy the code

This means that the class object of an object is retrieved through the Person.class method without calling any code blocks or code in the object. Instead, class.forname () calls the contents of a static code block.

The third way to print everything is obvious because you instantiate the object first.

Example Show scenario 2

Let’s combine these three methods to see some other effects.

First, we call three methods that get the Class object in sequence:

@Test public void test4() throws ClassNotFoundException { Class<? > clz = Person.class; System.out.println("---------------"); clz = Class.forName("com.choupangxia.reflect.Person"); System.out.println("---------------"); clz = new Person().getClass(); }Copy the code

Test4 The following logs are displayed:

-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the Person: static blocks of code -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the Person: dynamic code block Person: constructorCopy the code

After the class.forname () method executes a static code block, new Person().getClass() does not execute the same static code block. This also proves that a static code block is initialized only once.

Re-adjust the combination of the second scenario:

@Test public void test5() throws ClassNotFoundException { Class<? > clz = new Person().getClass(); System.out.println("---------------"); clz = Class.forName("com.choupangxia.reflect.Person"); }Copy the code

Test5 The following logs are displayed:

Person: static code block Person: dynamic code block Person: constructor ---------------Copy the code

The same operation that prints a static code block only once. Prove again that a static block of code in a class is initialized only once.

Example Show scenario 3

Here, we compare whether the Class objects obtained in the three forms are the same. The test code is as follows:

@Test public void test6() throws ClassNotFoundException { Class<? > clz1 = Person.class; Class<? > clz2 = Class.forName("com.choupangxia.reflect.Person"); Class<? > clz3 = new Person().getClass(); System.out.println(clz1 == clz2); System.out.println(clz2 == clz3); }Copy the code

Note that we used the equal sign above, which means we are comparing references. Guess the print?

true
trueCopy the code

The Class object obtained in all three forms is the same object. Why is that?

This involves the loading process of the class. We know that the loading process is divided into loading stage, connection stage and initialization stage.

The loading phase of a class reads binary data from the class file into memory, then converts the static storage structure represented by the byte stream into the runtime data structure in the method area, and generates a java.lang.class object of that class in the heap memory as an entry point to the method area data structure.

The end product of the class loading phase is the class object in the heap. No matter how many times a class is loaded, there is only one class object in the heap.

That is, whichever way you retrieve a Class object, you get the corresponding Class object in the heap.

Review the three forms

Class: The JVM will use the class loader, load the class into memory (if the class has not been loaded into memory yet), do no initialization of the class, and return the class object.

(2) class.forname (” Class name string “) : load the Class, and do the static initialization of the Class, return the Class object.

(3) instance object. GetClass () : static initialization, non-static initialization; Returns an object that refers to the Class of the object to which the runtime actually refers (the child’s reference is assigned to the parent’s reference variable).



Program new horizon