Respostas:
Talvez um exemplo que demonstre como os dois métodos são usados o ajudará a entender melhor as coisas. Portanto, considere a seguinte 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();
}
}
Conforme explicado em seu javadoc, a chamada retorna o objeto associado à classe ou interface com o nome da string, ou seja, retorna o que é afetado pela variável do tipo .Class.forName(String)
Class
test.Demo.class
clazz
Class
Em seguida, a chamada cria uma nova instância da classe representada por este objeto. A classe é instanciada como se por uma expressão com uma lista de argumentos vazia. Em outras palavras, isso aqui é realmente equivalente a e retorna uma nova instância de .clazz.newInstance()
Class
new
new Demo()
Demo
E a execução dessa Demo
classe imprime a seguinte saída:
Hi!
A grande diferença com o tradicional new
é que newInstance
permite instanciar uma classe que você não conhece até o tempo de execução, tornando seu código mais dinâmico.
Um exemplo típico é a API JDBC que carrega, em tempo de execução, o driver exato necessário para executar o trabalho. Contêineres EJBs, contêineres Servlet são outros bons exemplos: eles usam o carregamento dinâmico do tempo de execução para carregar e criar componentes que não sabiam nada antes do tempo de execução.
Na verdade, se você quiser ir além, dê uma olhada no artigo de Ted Neward, Entendendo Class.forName (), que eu estava parafraseando no parágrafo acima.
EDIT (respondendo a uma pergunta do OP postado como comentário): O caso dos drivers JDBC é um pouco especial. Conforme explicado no capítulo DriverManager de Introdução à API JDBC :
(...) Uma
Driver
classe é carregada e, portanto, automaticamente registrada noDriverManager
, de uma das duas maneiras:
chamando o método
Class.forName
. Isso carrega explicitamente a classe do driver. Como não depende de nenhuma configuração externa, essa maneira de carregar um driver é a recomendada para o uso daDriverManager
estrutura. O código a seguir carrega a classeacme.db.Driver
:Class.forName("acme.db.Driver");
Se
acme.db.Driver
foi gravado para que o carregamento faça com que uma instância seja criada e também chameDriverManager.registerDriver
essa instância como parâmetro (como deve ser o caso), ele estará naDriverManager
lista de drivers e estará disponível para criar uma conexão.(...)
Nos dois casos, é de responsabilidade da
Driver
classe recém-carregada se registrar chamandoDriverManager.registerDriver
. Como mencionado, isso deve ser feito automaticamente quando a classe é carregada.
Para se registrar durante a inicialização, o driver JDBC normalmente usa um bloco de inicialização estático como este:
package acme.db;
public class Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
...
}
A chamada Class.forName("acme.db.Driver")
causa a inicialização da acme.db.Driver
classe e, portanto, a execução do bloco de inicialização estática. E de Class.forName("acme.db.Driver")
fato "criará" uma instância, mas isso é apenas uma consequência de como (bom) Driver JDBC é implementado.
Como uma observação lateral, eu mencionaria que tudo isso não é mais necessário com o JDBC 4.0 (adicionado como um pacote padrão desde o Java 7) e o novo recurso de carregamento automático dos drivers JDBC 4.0. Consulte Aprimoramentos do JDBC 4.0 no Java SE 6 .
DriverManager.registerDriver
. A chamada Class.forName
de um driver JDBC causa sua inicialização e, portanto, a execução do bloco estático. Dê uma olhada em java2s.com/Open-Source/Java-Document/Database-DBMS/… para obter um exemplo. Portanto, esse é realmente um caso específico, devido aos componentes internos do driver.
Class.forName () fornece o objeto de classe, que é útil para reflexão. Os métodos que esse objeto possui são definidos por Java, não pelo programador que está escrevendo a classe. Eles são os mesmos para todas as classes. A chamada newInstance () fornece uma instância dessa classe (ou seja, chamá- Class.forName("ExampleClass").newInstance()
lo é equivalente a chamar new ExampleClass()
), na qual você pode chamar os métodos que a classe define, acessar os campos visíveis etc.
No mundo JDBC, a prática normal (de acordo com a API JDBC) é que você use Class#forName()
para carregar um driver JDBC. O driver JDBC deve se registrar DriverManager
dentro de um bloco estático:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class MyDriver implements Driver {
static {
DriverManager.registerDriver(new MyDriver());
}
public MyDriver() {
//
}
}
A chamada Class#forName()
executará todos os inicializadores estáticos . Dessa forma, é DriverManager
possível encontrar o driver associado entre os drivers registrados pelo URL de conexão, durante o getConnection()
qual aproximadamente se parece com:
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");
}
Mas também havia drivers JDBC com erros , começando com o org.gjt.mm.mysql.Driver
exemplo bem conhecido, que se registra incorretamente dentro do Construtor, em vez de um bloco estático:
package com.dbvendor.jdbc;
import java.sql.Driver;
import java.sql.DriverManager;
public class BadDriver implements Driver {
public BadDriver() {
DriverManager.registerDriver(this);
}
}
A única maneira de fazê-lo funcionar dinamicamente é ligar newInstance()
depois! Caso contrário, você enfrentará à primeira vista inexplicável "SQLException: no driver adequado". Mais uma vez, esse é um erro no driver JDBC, não no seu próprio código. Atualmente, nenhum driver JDBC deve conter esse bug. Então você pode (e deve) deixar de newInstance()
fora.
1: se você estiver interessado apenas no bloco estático da classe, o carregamento que a classe faria apenas e executaria blocos estáticos, tudo o que você precisa é:
Class.forName("Somthing");
2: se você estiver interessado em carregar a classe, execute seus blocos estáticos e também deseje acessar sua parte não estática, precisará de uma instância e, em seguida:
Class.forName("Somthing").newInstance();
"Class.forName ()" retorna o tipo de classe para o nome fornecido. "newInstance ()" retorna uma instância desta classe.
No tipo, você não pode chamar diretamente nenhum método de instância, mas pode usar apenas reflexão para a classe. Se você deseja trabalhar com um objeto da classe, é necessário criar uma instância (o mesmo que chamar "new MyClass ()").
Exemplo para "Class.forName ()"
Class myClass = Class.forName("test.MyClass");
System.out.println("Number of public methods: " + myClass.getMethods().length);
Exemplo para "Class.forName (). NewInstance ()"
MyClass myClass = (MyClass) Class.forName("test.MyClass").newInstance();
System.out.println("String representation of MyClass instance: " + myClass.toString());
apenas adicionando as respostas acima, quando temos um código estático (ou seja, o bloco de código é independente da instância) que precisa estar presente na memória, podemos ter a classe retornada, portanto, usaremos Class.forname ("someName") caso contrário Se não houver código estático, podemos procurar Class.forname (). newInstance ("someName"), pois ele carregará blocos de código no nível do objeto (não estáticos) na memória
Não importa quantas vezes você chame o método Class.forName (), apenas quando o bloco estático for executado, não várias vezes:
pacote forNameMethodDemo;
classe pública 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();
}
}
public class DemoClass {
static {
System.out.println("in Static block");
}
{
System.out.println("in Instance block");
}
}
a saída será:
in Static block
in Instance block
Esta in Static block
declaração é impressa apenas uma vez, não três vezes.
Class.forName () -> forName () é o método estático da classe Class; ele retorna o objeto de classe Class usado para reflexão e não o objeto de classe do usuário, portanto, você só pode chamar métodos de classe de classe como getMethods (), getConstructors () etc.
Se você se preocupa apenas em executar o bloco estático da sua classe (fornecida em tempo de execução) e obter apenas informações de métodos, construtores, Modificador etc. da sua classe, você pode fazer com esse objeto que você obtém usando Class.forName ()
Mas se você quiser acessar ou chamar seu método de classe (classe que você forneceu em tempo de execução), precisará do objeto para que o método newInstance da classe Class faça isso por você. Crie uma nova instância da classe e devolva-a para você . Você só precisa digitá-lo na sua classe.
ex: suponha que Employee seja sua classe então
Classe a = Class.forName (args [0]);
// args [0] = argumento de linha cmd para dar classe em tempo de execução.
Funcionário ob1 = a.newInstance ();
a.newInstance () é semelhante à criação de um objeto usando new Employee ().
agora você pode acessar todos os campos e métodos visíveis da sua classe.