web-dev-qa-db-ja.com

「Class.forName()」と「Class.forName()。newInstance()」の違いは何ですか?

Class.forName()Class.forName().newInstance()の違いは何ですか?

私は重要な違いを理解していません(私はそれらについて何かを読みました!)。手伝っていただけませんか?

156
Johanna

両方の方法がどのように使用されるかを示す例は、物事をよりよく理解するのに役立つかもしれません。したがって、次のクラスを検討してください。

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();
    }
}

Javadocで説明されているように、 Class.forName(String)を呼び出すと、指定された文字列名を持つクラスまたはインターフェイスに関連付けられたClassオブジェクトを返します。つまり、影響を受けるtest.Demo.classを返しますタイプclazzClass変数。

次に、 clazz.newInstance()を呼び出すと、このClassオブジェクトで表されるクラスの新しいインスタンスが作成されます。クラスは、空の引数リストを持つnew式によってインスタンス化されます。つまり、これは実際にはnew Demo()と同等であり、Demoの新しいインスタンスを返します。

したがって、このDemoクラスを実行すると、次の出力が出力されます。

Hi!

従来のnewとの大きな違いは、newInstanceを使用すると、実行時までわからないクラスをインスタンス化できるため、コードがより動的になります。

典型的な例は、実行時に作業の実行に必要な正確なドライバーをロードするJDBC APIです。 EJBコンテナー、サーブレットコンテナーは他の良い例です。動的ランタイムロードを使用して、ランタイム前には何も知らないコンポーネントをロードおよび作成します。

実際、さらに先に進みたい場合は、Ted Newardの論文をご覧ください nderstanding Class.forName() 上の段落で言い換えました。

EDIT(コメントとして投稿されたOPからの質問への回答):JDBCドライバーの場合は少し特別です。 JDBC API入門DriverManager の章で説明されているように:

(...)Driverクラスがロードされるため、次の2つの方法のいずれかでDriverManagerに自動的に登録されます。

  1. メソッドClass.forNameを呼び出します。これにより、ドライバークラスが明示的に読み込まれます。外部セットアップに依存しないため、このドライバのロード方法は、DriverManagerフレームワークを使用するための推奨方法です。次のコードは、クラスacme.db.Driverをロードします。

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

    acme.db.Driverが記述されており、それを読み込むとインスタンスが作成され、そのインスタンスをパラメーターとしてDriverManager.registerDriverを呼び出します(そうするべきです)、その後、DriverManagerのドライバーのリストにあり、接続の作成に使用できます。

  2. (...)

どちらの場合も、DriverManager.registerDriverを呼び出して自分自身を登録するのは、新しくロードされたDriverクラスの責任です。前述のように、これはクラスがロードされるときに自動的に実行される必要があります。

初期化中に自身を登録するために、JDBCドライバーは通常、次のような静的初期化ブロックを使用します。

package acme.db;

public class Driver {

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

    ...
}

Class.forName("acme.db.Driver")を呼び出すと、acme.db.Driverクラスが初期化され、静的初期化ブロックが実行されます。 Class.forName("acme.db.Driver")は実際にインスタンスを「作成」しますが、これはJDBCドライバーの実装方法(良い)の結果にすぎません。

追記として、JDBC 4.0(Java 7以降にデフォルトパッケージとして追加された)およびJDBC 4.0ドライバーの新しい自動ロード機能では、これはすべて不要になりました。 Java SE 6のJDBC 4.0拡張機能 を参照してください。

234
Pascal Thivent

Class.forName()は、リフレクションに役立つクラスオブジェクトを提供します。このオブジェクトが持つメソッドは、クラスを作成するプログラマーではなく、Javaによって定義されます。それらはすべてのクラスで同じです。その上でnewInstance()を呼び出すと、そのクラスのインスタンスが得られます(つまり、Class.forName("ExampleClass").newInstance()を呼び出すことは、new ExampleClass()を呼び出すことと同等です)。

35
Thomas Lötzer

JDBCの世界では、normalプラクティス(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() {
        //
    }

}

Class#forName()を呼び出すと、すべての 静的初期化子 が実行されます。このように、DriverManagerは、 getConnection() の間に接続URLによって登録済みドライバーの中から関連ドライバーを見つけることができます。

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");
}

しかし、よく知られている例としてorg.gjt.mm.mysql.Driverで始まるbuggyJDBCドライバーもあり、Constructor静的ブロックの代わりに:

package com.dbvendor.jdbc;

import Java.sql.Driver;
import Java.sql.DriverManager;

public class BadDriver implements Driver {

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

}

動的に機能させる唯一の方法は、後でnewInstance()を呼び出すことです!そうしないと、一見すると説明できない「SQLException:no適切なドライバー」に直面します。繰り返しますが、これはJDBCドライバーのbugであり、独自のコードではありません。現在、このバグを含むJDBCドライバーはありません。そのため、newInstance()を残しておくことができます(そして残すべきです)。

28
BalusC

1:クラスの静的ブロックのみに関心がある場合、クラスのロードのみが実行され、静的ブロックを実行する場合、必要なものは次のとおりです。

Class.forName("Somthing");

2:クラスの読み込みに興味があり、その静的ブロックを実行し、その非静的部分にもアクセスしたい場合は、インスタンスが必要で、次が必要です。

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

Class.forName()はクラスへの参照を取得し、Class.forName()。newInstance()はクラスの引数なしコンストラクタを使用して新しいインスタンスを返そうとします。

6
Gopi

上記の回答に追加するだけで、メモリに存在する必要がある静的コード(つまり、コードブロックはインスタンスに依存しない)がある場合、クラスを返すことができるため、Class.forname( "someName")を使用します。オブジェクトレベルのコードブロック(非静的)をメモリにロードするため、Class.forname()。newInstance( "someName")に使用できる静的コードはありません。

3
sij

「Class.forName()」は、指定された名前のClass-Typeを返します。 「newInstance()」は、このクラスのインスタンスを返します。

タイプでは、インスタンスメソッドを直接呼び出すことはできませんが、クラスのリフレクションのみを使用できます。クラスのオブジェクトを操作する場合は、そのインスタンスを作成する必要があります(「new MyClass()」を呼び出すのと同じです)。

「Class.forName()」の例

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

「Class.forName()。newInstance()」の例

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

Class.forName()-> forName()は、クラスクラスの静的メソッドであり、ユーザークラスオブジェクトではなく、リフレクションに使用されるクラスクラスオブジェクトを返します。そのため、getMethods()、getConstructors()などのクラスクラスメソッドのみを呼び出すことができます。

(Runtime given)クラスの静的ブロックのみを実行し、クラスのメソッド、コンストラクタ、修飾子などの情報のみを取得する場合は、Class.forName()を使用して取得するこのオブジェクトで実行できます

ただし、クラスメソッド(実行時に指定したクラス)にアクセスまたは呼び出したい場合は、クラスクラスのnewInstanceメソッドがそれを実行するようにオブジェクトを用意する必要があります。クラスの新しいインスタンスを作成して、それを返します。 。クラスに型キャストするだけです。

ex-:従業員があなたのクラスであると仮定します

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

// args [0] = cmd実行時のクラスを与える引数。

従業員ob1 = a.newInstance();

a.newInstance()は、new Employee()を使用してオブジェクトを作成することに似ています。

これで、クラスに表示されるすべてのフィールドとメソッドにアクセスできます。

0
Vinod Malkani