Qual é a diferença entre Class.forName()
e Class.forName().newInstance()
?
Eu não entendo a diferença significativa (eu li algo sobre eles!). Podes ajudar-me, por favor?
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 chamadaClass.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 chamarnew ExampleClass()
), na qual você pode chamar os métodos que a classe define, acessar os campos visíveis etc.fonte
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 registrarDriverManager
dentro de um bloco estático: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 ogetConnection()
qual aproximadamente se parece com: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: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 denewInstance()
fora.fonte
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 é:
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:
fonte
Class.forName () obtém uma referência a uma classe, Class.forName (). NewInstance () tenta usar o construtor no-arg da classe para retornar uma nova instância.
fonte
"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 ()"
Exemplo para "Class.forName (). NewInstance ()"
fonte
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
fonte
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:
classe pública MainClass {
}
public class DemoClass {
}
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.fonte
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.
fonte