回答:
おそらく、両方の方法がどのように使用されるかを示す例は、物事をよりよく理解するのに役立ちます。したがって、次のクラスを検討してください。
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)
Class
test.Demo.class
clazz
Class
次に、呼び出しにより、この オブジェクトで表されるクラスの新しいインスタンスが作成されます。このクラスは、引数リストが空の式によってインスタンス化されます。つまり、これは実際にはa と同じであり、の新しいインスタンスを返します。clazz.newInstance()
Class
new
new Demo()
Demo
Demo
したがって、このクラスを実行すると、次の出力が出力されます。
Hi!
伝統との大きな違いnew
IS newInstance
あなたのコードは、よりダイナミックな作り、実行時まで分からないというクラスをインスタンス化することができます。
典型的な例は、実行時に作業を実行するために必要な正確なドライバーをロードするJDBC APIです。EJBコンテナ、サーブレットコンテナは、他の良い例です。動的なランタイムロードを使用して、実行前には何も知らないコンポーネントをロードして作成します。
実際、さらに詳しく知りたい場合は、上の段落で言い換えたTed NewardのペーパーUnderstanding Class.forName()をご覧ください。
編集(コメントとして投稿されたOPからの質問への回答):JDBCドライバーの場合は少し特殊です。JDBC API入門のDriverManagerの章で説明されているように:
(...)
Driver
クラスが読み込まれ、次DriverManager
の2つの方法のいずれかで自動的にに登録されます。
メソッドを呼び出し
Class.forName
ます。これにより、ドライバークラスが明示的に読み込まれます。外部設定に依存しないため、DriverManager
フレームワークを使用する場合は、このドライバーのロード方法が推奨されます。次のコードはクラスをロードしますacme.db.Driver
。Class.forName("acme.db.Driver");
acme.db.Driver
をロードしてインスタンスを作成し、DriverManager.registerDriver
そのインスタンスをパラメーターとして(必要に応じて) 呼び出すように記述されている 場合DriverManager
、ドライバーのリストにあり、接続の作成に使用できます。(...)
これらのどちらの場合でも、
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の機能強化を参照してください。
DriverManager.registerDriver
。Class.forName
JDBCドライバーを呼び出すと、初期化が行われるため、静的ブロックが実行されます。例として、java2s.com / Open-Source / Java-Document / Database-DBMS /…をご覧ください。したがって、これは実際にはドライバの内部構造に起因する特定のケースです。
Class.forName()は、リフレクションに役立つクラスオブジェクトを提供します。このオブジェクトが持つメソッドは、クラスを作成するプログラマーではなく、Javaによって定義されます。それらはすべてのクラスで同じです。その上でnewInstance()を呼び出すClass.forName("ExampleClass").newInstance()
と、そのクラスのインスタンスが提供されます(つまり、それを呼び出すことはを呼び出すことと同じです)。そのインスタンスでnew ExampleClass()
、クラスが定義するメソッドを呼び出したり、可視フィールドにアクセスしたりできます。
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()
。
1:クラスの静的ブロックのみに関心がある場合、クラスのロードだけが実行され、静的ブロックが実行されます。必要なのは次のとおりです。
Class.forName("Somthing");
2:クラスのロードに興味があり、その静的ブロックを実行し、その非静的部分にもアクセスしたい場合は、インスタンスが必要であり、次のものが必要です。
Class.forName("Somthing").newInstance();
「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());
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回だけ出力されます。
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()を使用してオブジェクトを作成することに似ています。
これで、クラスに表示されるすべてのフィールドとメソッドにアクセスできます。