Was ist der Unterschied zwischen Class.forName()
und Class.forName().newInstance()
?
Ich verstehe den signifikanten Unterschied nicht (ich habe etwas darüber gelesen!). Kannst du mir bitte Helfen?
Vielleicht hilft Ihnen ein Beispiel, das zeigt, wie beide Methoden verwendet werden, die Dinge besser zu verstehen. Betrachten Sie also die folgende Klasse:
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();
}
}
Wie in seinem Javadoc erläutert, gibt der Aufruf das Objekt zurück, das der Klasse oder Schnittstelle mit dem angegebenen Zeichenfolgennamen zugeordnet ist, dh es wird zurückgegeben, was für die Variable vom Typ betroffen ist .Class.forName(String)
Class
test.Demo.class
clazz
Class
Durch das Aufrufen wird dann eine neue Instanz der Klasse erstellt, die von diesem Objekt dargestellt wird. Die Klasse wird wie durch einen Ausdruck mit einer leeren Argumentliste instanziiert . Mit anderen Worten, dies ist hier tatsächlich äquivalent zu a und gibt eine neue Instanz von zurück .clazz.newInstance()
Class
new
new Demo()
Demo
Wenn Sie diese Demo
Klasse ausführen, wird die folgende Ausgabe gedruckt:
Hi!
Der große Unterschied zum herkömmlichen System new
besteht darin, dass newInstance
eine Klasse, die Sie erst zur Laufzeit kennen, instanziiert werden kann, wodurch Ihr Code dynamischer wird.
Ein typisches Beispiel ist die JDBC-API, die zur Laufzeit den genauen Treiber lädt, der für die Ausführung der Arbeit erforderlich ist. EJBs-Container und Servlet-Container sind weitere gute Beispiele: Sie verwenden das dynamische Laden zur Laufzeit, um Komponenten zu laden und zu erstellen, von denen sie vor der Laufzeit nichts wissen.
Wenn Sie noch weiter gehen möchten, werfen Sie einen Blick auf Ted Newards Artikel Understanding Class.forName () , den ich im obigen Absatz umschrieben habe.
BEARBEITEN (Beantwortung einer Frage aus dem OP als Kommentar): Der Fall der JDBC-Treiber ist etwas Besonderes. Wie im DriverManager- Kapitel unter Erste Schritte mit der JDBC-API erläutert :
(...) Eine
Driver
Klasse wirdDriverManager
auf zwei Arten geladen und daher automatisch bei der registriert :
durch Aufrufen der Methode
Class.forName
. Dadurch wird die Treiberklasse explizit geladen. Da dies nicht von einem externen Setup abhängt, wird diese Art des Ladens eines Treibers für die Verwendung desDriverManager
Frameworks empfohlen . Der folgende Code lädt die Klasseacme.db.Driver
:Class.forName("acme.db.Driver");
Wenn dies
acme.db.Driver
so geschrieben wurde, dass beim Laden eine Instanz erstellt wird undDriverManager.registerDriver
diese Instanz auch als Parameter aufgerufen wird (wie dies der Fall sein sollte), befindet sie sich in derDriverManager
Treiberliste und steht zum Erstellen einer Verbindung zur Verfügung.(...)
In beiden Fällen liegt es in der Verantwortung der neu geladenen
Driver
Klasse, sich durch Aufruf zu registrierenDriverManager.registerDriver
. Wie bereits erwähnt, sollte dies automatisch erfolgen, wenn die Klasse geladen wird.
Um sich während der Initialisierung zu registrieren, verwendet der JDBC-Treiber normalerweise einen statischen Initialisierungsblock wie folgt:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
Der Aufruf Class.forName("acme.db.Driver")
bewirkt die Initialisierung der acme.db.Driver
Klasse und damit die Ausführung des statischen Initialisierungsblocks. Und Class.forName("acme.db.Driver")
wird in der Tat eine Instanz "erstellen", aber dies ist nur eine Folge davon, wie (gute) JDBC-Treiber implementiert werden.
Als Randnotiz möchte ich erwähnen, dass all dies mit JDBC 4.0 (seit Java 7 als Standardpaket hinzugefügt) und der neuen Funktion zum automatischen Laden von JDBC 4.0-Treibern nicht mehr erforderlich ist. Siehe JDBC 4.0-Verbesserungen in Java SE 6 .
DriverManager.registerDriver
. Das AufrufenClass.forName
eines JDBC-Treibers bewirkt dessen Initialisierung und damit die Ausführung des statischen Blocks. Werfen Sie einen Blick auf java2s.com/Open-Source/Java-Document/Database-DBMS/... für ein Beispiel. Dies ist also tatsächlich ein besonderer Fall aufgrund von Fahrerinternen.Class.forName () gibt Ihnen das Klassenobjekt, das für die Reflexion nützlich ist. Die Methoden dieses Objekts werden von Java definiert, nicht vom Programmierer, der die Klasse schreibt. Sie sind für jede Klasse gleich. Wenn Sie newInstance () aufrufen, erhalten Sie eine Instanz dieser Klasse (dh das Aufrufen
Class.forName("ExampleClass").newInstance()
entspricht dem Aufrufennew ExampleClass()
), auf der Sie die von der Klasse definierten Methoden aufrufen, auf die sichtbaren Felder zugreifen usw. können.quelle
In der JDBC-Welt wird normalerweise (gemäß der JDBC-API)
Class#forName()
ein JDBC-Treiber geladen. Der JDBC-Treiber sollte sich nämlich inDriverManager
einem statischen Block registrieren :Beim Aufrufen
Class#forName()
werden alle statischen Initialisierer ausgeführt . Auf diese WeiseDriverManager
kann der zugehörige Treiber unter den registrierten Treibern anhand der Verbindungs-URL gefunden werden,getConnection()
die ungefähr wie folgt aussieht:Aber es gab auch Buggy JDBC - Treiber, mit dem Start
org.gjt.mm.mysql.Driver
als bekanntes Beispiel, das sich falsch innerhalb der Register - Konstruktor anstelle eines statischen Block:Die einzige Möglichkeit, es dynamisch zum Laufen zu bringen, besteht darin,
newInstance()
danach anzurufen ! Andernfalls werden Sie auf den ersten Blick unerklärlichen "SQLException: kein geeigneter Fahrer" gegenüberstehen. Dies ist wiederum ein Fehler im JDBC-Treiber, nicht in Ihrem eigenen Code. Heutzutage sollte kein JDBC-Treiber diesen Fehler enthalten. Sie können (und sollten) also dasnewInstance()
weglassen.quelle
1: Wenn Sie nur an dem statischen Block der Klasse interessiert sind, würde das Laden der Klasse nur ausreichen und statische Blöcke ausführen, dann brauchen Sie nur:
2: Wenn Sie daran interessiert sind, die Klasse zu laden, ihre statischen Blöcke auszuführen und auch auf ihren nicht statischen Teil zugreifen möchten, benötigen Sie eine Instanz und dann:
quelle
Class.forName () erhält einen Verweis auf eine Klasse, Class.forName (). NewInstance () versucht, den Konstruktor no-arg für die Klasse zu verwenden, um eine neue Instanz zurückzugeben.
quelle
"Class.forName ()" gibt den Klassentyp für den angegebenen Namen zurück. "newInstance ()" gibt eine Instanz dieser Klasse zurück.
Für den Typ können Sie keine Instanzmethoden direkt aufrufen, sondern nur die Reflektion für die Klasse verwenden. Wenn Sie mit einem Objekt der Klasse arbeiten möchten, müssen Sie eine Instanz davon erstellen (wie beim Aufrufen von "new MyClass ()").
Beispiel für "Class.forName ()"
Beispiel für "Class.forName (). NewInstance ()"
quelle
Wenn wir nur einen statischen Code hinzufügen (dh der Codeblock ist instanzunabhängig), der im Speicher vorhanden sein muss, können wir die Klasse zurückgeben, sodass wir Class.forname ("someName") verwenden, wenn wir dies tun Wenn Sie keinen statischen Code haben, können Sie Class.forname (). newInstance ("someName") verwenden, da Codeblöcke auf Objektebene (nicht statisch) in den Speicher geladen werden
quelle
Unabhängig davon, wie oft Sie die Methode Class.forName () aufrufen, wird der statische Block nur einmal ausgeführt, nicht mehrmals:
öffentliche Klasse MainClass {
}}
öffentliche Klasse DemoClass {
}}
Ausgabe wird sein:
in Static block in Instance block
Diese
in Static block
Erklärung wird nur einmal und nicht dreimal gedruckt.quelle
Class.forName () -> forName () ist die statische Methode der Klassenklasse. Sie gibt das Klassenklassenobjekt zurück, das für die Reflexion verwendet wird, nicht das Benutzerklassenobjekt. Sie können also nur Klassenklassenmethoden wie getMethods (), getConstructors () usw. Aufrufen.
Wenn Sie nur den statischen Block Ihrer (zur Laufzeit angegebenen) Klasse ausführen und nur Informationen zu Methoden, Konstruktoren, Modifikatoren usw. Ihrer Klasse abrufen möchten, können Sie mit diesem Objekt arbeiten, das Sie mit Class.forName () erhalten.
Wenn Sie jedoch auf Ihre Klassenmethode (Klasse, die Sie zur Laufzeit angegeben haben) zugreifen oder diese aufrufen möchten, muss das Objekt so sein, dass die newInstance-Methode der Klassenklasse dies für Sie erledigt. Sie erstellt eine neue Instanz der Klasse und gibt sie an Sie zurück Sie müssen es nur in Ihre Klasse tippen.
Beispiel: Angenommen, der Mitarbeiter ist dann Ihre Klasse
Klasse a = Class.forName (args [0]);
// args [0] = cmd-Zeilenargument zur Angabe der Klasse zur Laufzeit.
Mitarbeiter ob1 = a.newInstance ();
a.newInstance () ähnelt dem Erstellen eines Objekts mit new Employee ().
Jetzt können Sie auf alle sichtbaren Felder und Methoden Ihrer Klasse zugreifen.
quelle