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


165

違いは何であるClass.forName()とはClass.forName().newInstance()

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

回答:


247

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

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で説明されているように、呼び出しは、指定された文字列名を持つクラスまたはインターフェースに関連付けられオブジェクト返します。つまり、type の変数に影響を受けるものを返します。Class.forName(String) Classtest.Demo.classclazzClass

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

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

Hi!

伝統との大きな違いnewIS newInstanceあなたのコードは、よりダイナミックな作り、実行時まで分からないというクラスをインスタンス化することができます。

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

実際、さらに詳しく知りたい場合は、上の段落で言い換えたTed NewardのペーパーUnderstanding Class.forName()をご覧ください。

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

(...)Driverクラスが読み込まれ、次DriverManagerの2つの方法のいずれかで自動的にに登録されます。

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

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

    acme.db.Driverをロードしてインスタンスを作成し、DriverManager.registerDriverそのインスタンスをパラメーターとして(必要に応じて) 呼び出すように記述されている 場合DriverManager、ドライバーのリストにあり、接続の作成に使用できます。

  2. (...)

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

初期化中に自分自身を登録するために、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の機能強化を参照してください。



2
上記のサイトでは、「Class.forNameを呼び出すと、自動的にドライバーのインスタンスが作成され、DriverManagerに登録されるため、クラスのインスタンスを作成する必要はありません。独自のインスタンスを作成する場合は、 、不要な複製を作成することになりますが、害はありません。」これは、Class.forNameによってインスタンスを自動的に作成し、もう一方を作成する場合は不要なインスタンスを作成することを意味します。したがって、Calss.forName()とClass.forName()。newInstance()の両方が運転者!!
Johanna

10
JDBCドライバーは「特別」であり、インスタンスが作成され、のパラメーターとして渡される静的な初期化ブロックで記述されますDriverManager.registerDriverClass.forNameJDBCドライバーを呼び出すと、初期化が行われるため、静的ブロックが実行されます。例として、java2s.com / Open-Source / Java-Document / Database-DBMS /…ご覧ください。したがって、これは実際にはドライバの内部構造に起因する特定のケースです。
Pascal Thivent、2010年

1
私がであることを気づいた別の答え Class.newInstance()強くお勧めを使用して、。Class.getConstructor()を使用し、次にConstructor.newInstance()を使用することをお勧めします。可能な例外のマスクを回避します。
LS

「newInstanceを使用すると、実行時までわからないクラスをインスタンス化できます」が私の一日を作りました。ありがとう。
コード熱狂的

37

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


29

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() {
        //
    }

}

呼び出す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");
}

しかし、よく知られている例から始まる、バグのある 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);
    }

}

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


17

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

Class.forName("Somthing");

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

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

正解です。明確で簡潔!
gaurav

6

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


3

「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

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


1

Class.forName()メソッドを何回呼び出しても、静的ブロックが一度だけ実行された場合に限られます。

パッケージforNameMethodDemo;

パブリッククラス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();
    }

}

パブリッククラスDemoClass {

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

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

}

出力は次のようになります。

in Static block in Instance block

このin Static blockステートメントは、3回ではなく1回だけ出力されます。


0

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

your(Runtime given)クラスの静的ブロックのみを実行し、クラスのメソッド、コンストラクター、モディファイアなどの情報のみを取得することに関心がある場合は、Class.forName()を使用して取得するこのオブジェクトで実行できます。

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

例:従業員があなたのクラスであるとします

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

// args [0] =実行時にクラスを指定するcmd行引数。

従業員ob1 = a.newInstance();

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.