Java “Class.forName()”和“Class.forName().newInstance()”有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2092659/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 03:27:18  来源:igfitidea点击:

What is the difference between "Class.forName()" and "Class.forName().newInstance()"?

javaclass

提问by Johanna

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

Class.forName()和 和有Class.forName().newInstance()什么区别?

I do not understand the significant difference (I have read something about them!). Could you please help me?

我不明白其中的显着差异(我已经阅读了一些关于它们的内容!)。请你帮助我好吗?

采纳答案by Pascal Thivent

Maybe an example demonstrating how both methods are used will help you to understand things better. So, consider the following class:

也许一个演示如何使用这两种方法的示例将帮助您更好地理解事物。因此,请考虑以下类:

package test;

public class Demo {

    public Demo() {
        System.out.println("Hi!");
    }

    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("test.Demo");
        Demo demo = (Demo) clazz.newInstance();
    }
}

As explained in its javadoc, calling Class.forName(String)returns the Classobject associated with the class or interface with the given string namei.e. it returns test.Demo.classwhich is affected to the clazzvariable of type Class.

正如在其 javadoc 中所解释的,调用返回与具有给定字符串名称的类或接口关联对象,即它返回影响type 变量的对象。Class.forName(String)Classtest.Demo.classclazzClass

Then, calling clazz.newInstance()creates a new instance of the class represented by this Classobject. The class is instantiated as if by a newexpression with an empty argument list.In other words, this is here actually equivalent to a new Demo()and returns a new instance of Demo.

然后,调用创建此对象表示的类的新实例该类被实例化为一个带有空参数列表表达式。换句话说,这里实际上相当于 a并返回 的一个新实例。clazz.newInstance()Classnewnew Demo()Demo

And running this Democlass thus prints the following output:

Demo因此运行这个类会打印以下输出:

Hi!

The big difference with the traditional newis that newInstanceallows to instantiate a class that you don't know until runtime, making your code more dynamic.

与传统的最大区别new在于,它newInstance允许实例化一个您直到运行时才知道的类,从而使您的代码更具动态性。

A typical example is the JDBC API which loads, at runtime, the exact driver required to perform the work. EJBs containers, Servlet containers are other good examples: they use dynamic runtime loading to load and create components they don't know anything before the runtime.

一个典型的例子是 JDBC API,它在运行时加载执行工作所需的确切驱动程序。EJB 容器、Servlet 容器是其他很好的例子:它们使用动态运行时加载来加载和创建在运行时之前不知道的组件。

Actually, if you want to go further, have a look at Ted Neward paper Understanding Class.forName()that I was paraphrasing in the paragraph just above.

实际上,如果您想更进一步,请查看我在上面段落中释义的Ted Neward 论文Understanding Class.forName()

EDIT(answering a question from the OP posted as comment): The case of JDBC drivers is a bit special. As explained in the DriverManagerchapter of Getting Started with the JDBC API:

编辑(回答作为评论发布的 OP 中的一个问题):JDBC 驱动程序的情况有点特殊。如JDBC API 入门DriverManager章节所述

(...) A Driverclass is loaded, and therefore automatically registered with the DriverManager, in one of two ways:

  1. by calling the method Class.forName. This explicitly loads the driver class. Since it does not depend on any external setup, this way of loading a driver is the recommended one for using the DriverManagerframework. The following code loads the class acme.db.Driver:

    Class.forName("acme.db.Driver");
    

    If acme.db.Driverhas been written so that loading it causes an instance to be created and also calls DriverManager.registerDriverwith that instance as the parameter(as it should do), then it is in the DriverManager's list of drivers and available for creating a connection.

  2. (...)

In both of these cases, it is the responsibility of the newly-loaded Driverclass to register itself by calling DriverManager.registerDriver. As mentioned, this should be done automatically when the class is loaded.

(...) 一个Driver类被加载,因此自动注册到DriverManager,以两种方式之一:

  1. 通过调用方法Class.forName。这显式加载驱动程序类。由于它不依赖于任何外部设置,因此推荐使用这种加载驱动程序的方式来使用该DriverManager框架。以下代码加载类acme.db.Driver

    Class.forName("acme.db.Driver");
    

    如果acme.db.Driver已编写为加载它会导致创建一个实例并 DriverManager.registerDriver使用该实例作为参数调用(正如它应该做的那样),则它位于 的 DriverManager驱动程序列表中并可用于创建连接。

  2. (……)

在这两种情况下,新加载的Driver类都有责任通过调用DriverManager.registerDriver. 如前所述,这应该在加载类时自动完成。

To register themselves during initialization, JDBC driver typically use a static initialization block like this:

要在初始化期间注册自己,JDBC 驱动程序通常使用静态初始化块,如下所示:

package acme.db;

public class Driver {

    static {
        java.sql.DriverManager.registerDriver(new Driver());
    }

    ...
}

Calling Class.forName("acme.db.Driver")causes the initialization of the acme.db.Driverclass and thus the execution of the static initialization block. And Class.forName("acme.db.Driver")will indeed "create" an instance but this is just a consequence of how (good) JDBC Driver are implemented.

调用Class.forName("acme.db.Driver")会导致acme.db.Driver类的初始化,从而导致静态初始化块的执行。并且 Class.forName("acme.db.Driver")确实会“创建”一个实例,但这只是(好的)JDBC 驱动程序实现方式的结果。

As a side note, I'd mention that all this is not required anymore with JDBC 4.0(added as a default package since Java 7) and the new auto-loading feature of JDBC 4.0 drivers. See JDBC 4.0 enhancements in Java SE 6.

作为旁注,我要提到 JDBC 4.0(自 Java 7 以来作为默认包添加)和 JDBC 4.0 驱动程序的新自动加载功能不再需要所有这些。请参阅Java SE 6 中的 JDBC 4.0 增强功能

回答by Thomas L?tzer

Class.forName() gives you the class object, which is useful for reflection. The methods that this object has are defined by Java, not by the programmer writing the class. They are the same for every class. Calling newInstance() on that gives you an instance of that class (i.e. calling Class.forName("ExampleClass").newInstance()it is equivalent to calling new ExampleClass()), on which you can call the methods that the class defines, access the visible fields etc.

Class.forName() 为您提供类对象,这对于反射很有用。该对象具有的方法是由 Java 定义的,而不是由编写类的程序员定义的。它们对每个班级都是一样的。调用 newInstance() 为您提供该类的一个实例(即调用Class.forName("ExampleClass").newInstance()它相当于调用new ExampleClass()),您可以在该实例上调用类定义的方法,访问可见字段等。

回答by Arne Deutsch

"Class.forName()" returns the Class-Type for the given name. "newInstance()" does return an instance of this class.

“Class.forName()”返回给定名称的类类型。“newInstance()”确实返回此类的一个实例。

On the type you can't call directly any instance methods but can only use reflection for the class. If you want to work with an object of the class you have to create an instance of it (same as calling "new MyClass()").

在类型上,您不能直接调用任何实例方法,而只能对类使用反射。如果要使用类的对象,则必须创建它的实例(与调用“new MyClass()”相同)。

Example for "Class.forName()"

“Class.forName()”示例

Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);

Example for "Class.forName().newInstance()"

“Class.forName().newInstance()”的示例

MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());

回答by Gopi

Class.forName() gets a reference to a Class, Class.forName().newInstance() tries to use the no-arg constructor for the Class to return a new instance.

Class.forName() 获取对 Class 的引用,Class.forName().newInstance() 尝试使用 Class 的无参数构造函数返回一个新实例。

回答by BalusC

In JDBC world, the normalpractice (according the JDBC API) is that you use Class#forName()to load a JDBC driver. The JDBC driver should namely register itself in DriverManagerinside a static block:

在 JDBC 世界中,通常的做法(根据 JDBC API)是您Class#forName()用来加载 JDBC 驱动程序。JDBC 驱动程序应该DriverManager在一个静态块中注册自己:

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class MyDriver implements Driver {

    static {
        DriverManager.registerDriver(new MyDriver());
    }

    public MyDriver() {
        //
    }

}

Invoking Class#forName()will execute all static initializers. This way the DriverManagercan find the associated driver among the registered drivers by connection URL during getConnection()which roughly look like follows:

调用Class#forName()将执行所有静态初始值设定项。这样就DriverManager可以通过连接 URL 在已注册的驱动程序中找到关联的驱动程序getConnection(),大致如下所示:

public static Connection getConnection(String url) throws SQLException {
    for (Driver driver : registeredDrivers) {
        if (driver.acceptsURL(url)) {
            return driver.connect(url);
        }
    }
    throw new SQLException("No suitable driver");
}

But there were also buggyJDBC drivers, starting with the org.gjt.mm.mysql.Driveras well known example, which incorrectly registers itself inside the Constructorinstead of a static block:

但是也有错误的JDBC 驱动程序,从org.gjt.mm.mysql.Driver众所周知的示例开始,它错误地将自身注册到构造函数而不是静态块中:

package com.dbvendor.jdbc;

import java.sql.Driver;
import java.sql.DriverManager;

public class BadDriver implements Driver {

    public BadDriver() {
        DriverManager.registerDriver(this);
    }

}

The only way to get it to work dynamically is to call newInstance()afterwards! Otherwise you will face at first sight unexplainable "SQLException: no suitable driver". Once again, this is a bugin the JDBC driver, not in your own code. Nowadays, no one JDBC driver should contain this bug. So you can (and should) leave the newInstance()away.

让它动态工作的唯一方法是newInstance()事后调用!否则,您将第一眼看到无法解释的“SQLException:没有合适的驱动程序”。再次强调,这是JDBC 驱动程序中的错误,而不是您自己的代码中的错误。如今,没有任何 JDBC 驱动程序应该包含此错误。所以你可以(也应该)离开newInstance()

回答by sij

just adding to above answers, when we have a static code (ie code block is instance independent) that needs to be present in memory, we can have the class returned so we'll use Class.forname("someName") else if we dont have static code we can go for Class.forname().newInstance("someName") as it will load object level code blocks(non static) to memory

只是添加到上面的答案,当我们有一个需要存在于内存中的静态代码(即代码块是独立于实例的)时,我们可以返回该类,因此我们将使用 Class.forname("someName") else 如果我们没有静态代码,我们可以使用 Class.forname().newInstance("someName") 因为它会将对象级代码块(非静态)加载到内存中

回答by Hussain Akhtar Wahid 'Ghouri'

1 : if you are interested only in the static block of the class , the loading the class only would do , and would execute static blocks then all you need is:

1:如果你只对类的静态块感兴趣,加载类只会做,并且会执行静态块,那么你需要的是:

Class.forName("Somthing");

2 : if you are interested in loading the class , execute its static blocks and also want to access its its non static part , then you need an instance and then you need:

2:如果您有兴趣加载类,执行其静态块并希望访问其非静态部分,那么您需要一个实例,然后您需要:

Class.forName("Somthing").newInstance();

回答by Vinod Malkani

Class.forName()-->forName() is the static method of Class class it returns Class class object used for reflection not user class object so you can only call Class class methods on it like getMethods(),getConstructors() etc.

Class.forName()-->forName() 是 Class 类的静态方法,它返回用于反射的 Class 类对象而不是用户类对象,因此您只能在其上调用 Class 类方法,如 getMethods()、getConstructors() 等。

If you care about only running static block of your(Runtime given) class and only getting information of methods,constructors,Modifier etc of your class you can do with this object which you get using Class.forName()

如果您只关心运行您的(运行时给定的)类的静态块并且只获取类的方法、构造函数、修饰符等的信息,您可以使用 Class.forName() 获得的这个对象

But if you want to access or call your class method (class which you have given at runtime) then you need to have its object so newInstance method of Class class do it for you.It create new instance of the class and return it to you .You just need to type-cast it to your class.

但是如果你想访问或调用你的类方法(你在运行时给出的类)那么你需要有它的对象,所以类类的 newInstance 方法为你做。它创建类的新实例并将它返回给你.你只需要将它类型转换到你的班级。

ex-: suppose Employee is your class then

ex-: 假设 Employee 是你的班级

Class a=Class.forName(args[0]);

类 a=Class.forName(args[0]);

//args[0]=cmd line argument to give class at runtime.

//args[0]=cmd 行参数在运行时给出类。

Employee ob1=a.newInstance();

员工 ob1=a.newInstance();

a.newInstance() is similar to creating object using new Employee().

a.newInstance() 类似于使用 new Employee() 创建对象。

now you can access all your class visible fields and methods.

现在您可以访问所有类可见的字段和方法。

回答by Priyanka Wagh

No matter how many times you call Class.forName() method, Only once the static block gets executed not multiple time:

无论您调用 Class.forName() 方法多少次,静态块只执行一次而不是多次:

package forNameMethodDemo;

包名称方法演示;

public class MainClass {

公共类主类{

    public static void main(String[] args) throws Exception {
        Class.forName("forNameMethodDemo.DemoClass");
        Class.forName("forNameMethodDemo.DemoClass");
        Class.forName("forNameMethodDemo.DemoClass");
        DemoClass demoClass = (DemoClass)Class.forName("forNameMethodDemo.DemoClass").newInstance();
    }

}

}

public class DemoClass {

公共类演示类{

static {
    System.out.println("in Static block");
}

{
    System.out.println("in Instance block");
}

}

}

output will be:

输出将是:

in Static block in Instance block

in Static block in Instance block

This in Static blockstatement is printed only once not three times.

这个in Static block语句只打印一次而不是三次。