How does the JVM judge that the classes are the same

 The JVM judges according to two aspects: one is the full name of the class; the other is the class loader.

The full name of the class is the same, is the class loader the same?

Even if the full name of the class is the same, but the loader used is different, the Class objects are different.

 

package com.test;

public class TestClass {
	
	public static void main(String[] args){

		try {
			// Load classes dynamically, test Class.forName()
			Class testTypeForName = Class.forName("com.test.TestClassType");
			System.out.println("testForName---" + testTypeForName);
			// test class loader
			System.out.println("Loader in the form of forName --"
					+ testTypeForName.getClassLoader());

			System.out.println();
			
			try {
				TestClassType tp = (TestClassType) testTypeForName.newInstance();
			} catch (InstantiationException e) {
				// TODO Auto-generated catch block
				e.printStackTrace ();
			} catch (IllegalAccessException e) {
				// TODO Auto-generated catch block
				e.printStackTrace ();
			}
			System.out.println("Loader in the form of forName --"
					+ testTypeForName.getClassLoader());
			System.out.println();
			
			// test class name.class
			Class testTypeClass = TestClassType.class;
			System.out.println("testTypeClass---" + testTypeClass);
			System.out.println("Loader in the form of class---"
					+ testTypeClass.getClassLoader());

			System.out.println();
			
			// Test Object.getClass()
			TestClassType testGetClass = new TestClassType();
			System.out.println("testGetClass---" + testGetClass.getClass());
			System.out.println("Loader in the form of getClass --"
					+ testGetClass.getClass().getClassLoader());

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace ();
		}
	}
}



class TestClassType {

	// Constructor
	public TestClassType() {
		System.out.println("----Constructor---");
	}

	// static parameter initialization
	static {
		System.out.println("---Static parameter initialization---");
	}

	// non-static parameter initialization
	{
		System.out.println("----Non-static parameter initialization---");
	}
}

 

result:

---Static parameter initialization---
testForName---class com.test.TestClassType
Loaders of the form forName --sun.misc.Launcher$AppClassLoader@6b97fd

----Non-static parameter initialization---
----Constructor---
Loaders of the form forName --sun.misc.Launcher$AppClassLoader@6b97fd

testTypeClass---class com.test.TestClassType
Loader in the form of class---sun.misc.Launcher$AppClassLoader@6b97fd

----Non-static parameter initialization---
----Constructor---
testGetClass---class com.test.TestClassType
Loaders of the form getClass --sun.misc.Launcher$AppClassLoader@6b97fd

 

Observation found that the three forms of loader are the same.

The same conditions for classes in jvm: class loader instance + package name + class name

And the same class in java: package name + class name

 

1. When to use Class.forName()?

Let's warm up first, give you a string variable, which represents the package name and class name of a class, how do you instantiate it? Your first thought must be new, but pay attention:

A a = (A)Class.forName(“pacage.A”).newInstance();

This has the same effect as your A a = new A();

 

Closer to home now.

Dynamically load and create Class objects, such as when you want to create objects based on strings entered by the user:

String str = "User input string";

Class t = Class.forName(str);

t.newInstance();

 

When initializing a class and generating an instance, what is the main difference between the newInstance() method and the new keyword, except that one is a method and the other is a keyword?

 

The difference between them is the way to create objects, the former is to use the class loading mechanism, the latter is to create a new class .

So why are there two ways to create objects? This mainly considers software design ideas such as scalability, extensibility and reusability of software.

 

From the JVM's point of view, when we use the keyword new to create a class, the class can be unloaded . But when using the newInstance() method, you must ensure that:

1. This class has been loaded;

2. This class is already connected.

It is the static method forName() of Class that completes the above two steps. This static method calls the startup class loader, that is, the loader that loads the java API.

 

Now it can be seen that newInstance() actually decomposes the new method into two steps, that is, first call the Class loading method to load a class, and then instantiate it.

The benefits of this step-by-step approach are obvious. We can get better flexibility when calling the static loading method forName of the class, which provides a means of decoupling.

 

2. What is the difference between new and Class.forName()?

In fact, some of the above have been mentioned, so here is a summary:

First, newInstance( ) is a method, and new is a keyword ;

Secondly, the use of newInstance() under Class is limited, because the object it generates can only call the constructor without parameters , and the object generated by the new keyword does not have this limitation.

In short:

newInstance(): Weak type, inefficient, can only call the no-argument construction.

new: Strongly typed, relatively efficient, can call any public construct.

Class.forName("") returns the class.

Class.forName("").newInstance() returns object.

 

 

3. Why is Class.forName( ) useful when loading the database driver package, but newInstance( ) is not called?

In Java development, especially database development, the Class.forName() method is often used.

 

 有数据库开发经验朋友会发现,为什么在我们加载数据库驱动包的时候有的却没有调用newInstance( )方法呢?即有的jdbc连接数据库的写法里是Class.forName(xxx.xx.xx);而有一 些:Class.forName(xxx.xx.xx).newInstance(),为什么会有这两种写法呢?

   刚才提到,Class.forName("");的作用是要求JVM查找并加载指定的类,如果在类中有静态初始化器的话,JVM必然会执行该类的静态代码 段。而在JDBC规范中明确要求这个Driver类必须向DriverManager注册自己,即任何一个JDBC Driver的 Driver类的代码都必须类似如下:

  public class MyJDBCDriver implements Driver {

   static {

     DriverManager.registerDriver(new MyJDBCDriver());

  }

  }

 既然在静态初始化器的中已经进行了注册,所以我们在使用JDBC时只需要Class.forName(XXX.XXX);就可以了。

 

贴出Proxool 连接池的静态初始化方法:

public class ProxoolDriver implements Driver {

    private static final Log LOG = LogFactory.getLog(ProxoolDriver.class);

    static {
        try {
            DriverManager.registerDriver(new ProxoolDriver());
        } catch (SQLException e) {
            System.out.println(e.toString());
        }
    }
}

 

 

...

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326011756&siteId=291194637