Risposte:
Forse un esempio che dimostra come vengono utilizzati entrambi i metodi ti aiuterà a capire meglio le cose. Quindi, considera la seguente classe:
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();
}
}
Come spiegato nel suo javadoc, la chiamata restituisce l' oggetto associato alla classe o all'interfaccia con il nome di stringa dato, cioè restituisce quale è influenzato dalla variabile di tipo .Class.forName(String)
Class
test.Demo.class
clazz
Class
Quindi, chiamando crea una nuova istanza della classe rappresentata da questo oggetto. La classe viene istanziata come da un'espressione con un elenco di argomenti vuoto. In altre parole, questo è effettivamente equivalente a e restituisce una nuova istanza di .clazz.newInstance()
Class
new
new Demo()
Demo
E l'esecuzione di questa Demo
classe stampa quindi il seguente output:
Hi!
La grande differenza con il tradizionale new
è che newInstance
consente di creare un'istanza di una classe che non si conosce fino al runtime, rendendo il codice più dinamico.
Un tipico esempio è l'API JDBC che carica, in fase di esecuzione, il driver esatto richiesto per eseguire il lavoro. I contenitori EJB, i contenitori servlet sono altri buoni esempi: usano il caricamento dinamico del runtime per caricare e creare componenti che non sanno nulla prima del runtime.
In realtà, se vuoi andare oltre, dai un'occhiata al documento di Ted Neward Understanding Class.forName () che stavo parafrasando nel paragrafo sopra.
EDIT (rispondendo a una domanda dell'OP pubblicata come commento): il caso dei driver JDBC è un po 'speciale. Come spiegato nel capitolo DriverManager di Introduzione all'API JDBC :
(...) Una
Driver
classe viene caricata, e quindi automaticamente registrata conDriverManager
, in uno dei due modi seguenti:
chiamando il metodo
Class.forName
. Questo carica esplicitamente la classe del driver. Poiché non dipende da alcuna configurazione esterna, questo modo di caricare un driver è quello consigliato per l'utilizzo delDriverManager
framework. Il codice seguente carica la classeacme.db.Driver
:Class.forName("acme.db.Driver");
Se
acme.db.Driver
è stato scritto in modo tale che il caricamento causi la creazione di un'istanza e la chiama ancheDriverManager.registerDriver
con quell'istanza come parametro (come dovrebbe fare), allora èDriverManager
nell'elenco dei driver e disponibile per la creazione di una connessione.(...)
In entrambi questi casi, è responsabilità della
Driver
classe appena caricata registrarsi chiamandoDriverManager.registerDriver
. Come accennato, questo dovrebbe essere fatto automaticamente quando la classe viene caricata.
Per registrarsi durante l'inizializzazione, il driver JDBC utilizza in genere un blocco di inizializzazione statico come questo:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
La chiamata Class.forName("acme.db.Driver")
provoca l'inizializzazione della acme.db.Driver
classe e quindi l'esecuzione del blocco di inizializzazione statica. E Class.forName("acme.db.Driver")
in effetti "creerà" un'istanza, ma questa è solo una conseguenza di come (buono) driver JDBC sono implementati.
Come nota a margine, vorrei menzionare che tutto ciò non è più necessario con JDBC 4.0 (aggiunto come pacchetto predefinito da Java 7) e la nuova funzionalità di caricamento automatico dei driver JDBC 4.0. Vedi i miglioramenti di JDBC 4.0 in Java SE 6 .
DriverManager.registerDriver
. La chiamata Class.forName
a un driver JDBC provoca la sua inizializzazione e quindi l'esecuzione del blocco statico. Dai un'occhiata a java2s.com/Open-Source/Java-Document/Database-DBMS/… per un esempio. Quindi questo è in realtà un caso particolare a causa dei driver interni.
Class.forName () ti dà l'oggetto di classe, che è utile per la riflessione. I metodi che ha questo oggetto sono definiti da Java, non dal programmatore che scrive la classe. Sono gli stessi per ogni classe. Chiamare newInstance () su che ti dà un'istanza di quella classe (cioè chiamarla Class.forName("ExampleClass").newInstance()
equivale a chiamare new ExampleClass()
), su cui puoi chiamare i metodi che la classe definisce, accedere ai campi visibili ecc.
Nel mondo JDBC, la pratica normale (secondo l'API JDBC) è che si utilizza Class#forName()
per caricare un driver JDBC. Il driver JDBC dovrebbe in particolare registrarsi DriverManager
all'interno di un blocco statico:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class MyDriver implements Driver {
static {
DriverManager.registerDriver(new MyDriver());
}
public MyDriver() {
//
}
}
Il richiamo Class#forName()
eseguirà tutti gli inizializzatori statici . In questo modo è DriverManager
possibile trovare il driver associato tra i driver registrati tramite l'URL di connessione durante il getConnection()
quale appare approssimativamente il seguente:
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");
}
Ma c'erano anche driver JDBC difettosi , a partire dal org.gjt.mm.mysql.Driver
tanto noto esempio, che si registra erroneamente all'interno del costruttore anziché in un blocco statico:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class BadDriver implements Driver {
public BadDriver() {
DriverManager.registerDriver(this);
}
}
L'unico modo per farlo funzionare in modo dinamico è chiamare newInstance()
dopo! Altrimenti dovrai affrontare a prima vista inspiegabile "SQLException: nessun driver adatto". Ancora una volta, questo è un bug nel driver JDBC, non nel tuo codice. Al giorno d'oggi, nessun driver JDBC dovrebbe contenere questo errore. Quindi puoi (e dovresti) lasciare la newInstance()
strada.
1: se sei interessato solo al blocco statico della classe, il caricamento della sola classe lo farebbe ed eseguirà blocchi statici quindi tutto ciò che ti serve è:
Class.forName("Somthing");
2: se sei interessato a caricare la classe, esegui i suoi blocchi statici e vuoi anche accedere alla sua parte non statica, allora hai bisogno di un'istanza e quindi hai bisogno di:
Class.forName("Somthing").newInstance();
"Class.forName ()" restituisce il tipo di classe per il nome specificato. "newInstance ()" restituisce un'istanza di questa classe.
Sul tipo non è possibile chiamare direttamente alcun metodo di istanza ma è possibile utilizzare solo la riflessione per la classe. Se vuoi lavorare con un oggetto della classe devi crearne un'istanza (come chiamare "new MyClass ()").
Esempio per "Class.forName ()"
Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);
Esempio per "Class.forName (). NewInstance ()"
MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
aggiungendo solo le risposte sopra, quando abbiamo un codice statico (cioè il blocco di codice è indipendente dall'istanza) che deve essere presente in memoria, possiamo avere la classe restituita, quindi useremo Class.forname ("someName") altrimenti se noi non abbiamo un codice statico, possiamo usare Class.forname (). newInstance ("someName") in quanto caricherà blocchi di codice a livello di oggetto (non statici) in memoria
Indipendentemente da quante volte si chiama il metodo Class.forName (), solo una volta che il blocco statico viene eseguito non più volte:
pacchetto perNomeMetodoDemo;
classe pubblica 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 di classe pubblica {
static {
System.out.println("in Static block");
}
{
System.out.println("in Instance block");
}
}
l'output sarà:
in Static block
in Instance block
Questa in Static block
affermazione viene stampata solo una volta e non tre volte.
Class.forName () -> forName () è il metodo statico della classe Class che restituisce l'oggetto classe Class utilizzato per la riflessione non oggetto classe utente quindi è possibile chiamare solo metodi di classe Class su di esso come getMethods (), getConstructors () ecc.
Se ti interessa solo eseguire il blocco statico della tua classe (Runtime dato) e ottenere solo informazioni su metodi, costruttori, modificatore ecc. Della tua classe, puoi fare con questo oggetto che ottieni usando Class.forName ()
Ma se vuoi accedere o chiamare il tuo metodo di classe (classe che hai dato in fase di runtime) allora devi avere il suo oggetto così newInstance metodo della classe Class farlo per te. Crea una nuova istanza della classe e te lo restituisce Devi solo lanciarlo nella tua classe.
es: supponiamo che il dipendente sia la tua classe allora
Class a = Class.forName (args [0]);
// args [0] = argomento della riga cmd per fornire la classe in fase di esecuzione.
Employee ob1 = a.newInstance ();
a.newInstance () è simile alla creazione di un oggetto utilizzando new Employee ().
ora puoi accedere a tutti i campi e metodi visibili della tua classe.