Class.forName () vs ClassLoader.loadClass () – qual usar para carregamento dynamic?

Ao carregar dinamicamente uma class, quando é apropriado usar

Class.forName("SomeClass"); 

e quando devo usar

 ClassLoader.getSystemClassLoader().loadClass("SomeClass"); 

Ou são duas maneiras de fazer a mesma coisa?

Eles são bem diferentes!

Conforme declarado na documentação de Class.forName(String) ,

Retorna o object Class associado à class ou interface com o nome da string fornecido. Invocar esse método é equivalente a: Class.forName(className, true, currentLoader)

( true aqui se refere a você deseja inicializar a class? )

Por outro lado, ClassLoader.loadClass(String) :

Invocar esse método é equivalente a chamar loadClass(name, false) .

(aqui, o booleano não tem nada a ver com a boot; mas se você verificar a documentação do loadClass (String, boolean), verá que tudo o que ele faz é carregar a class, não inicializá-la).

O primeiro ( Class.forName("SomeClass"); ):

  • use o carregador de class que carregou a class que chama esse código
  • inicializar a class (ou seja, todos os inicializadores estáticos serão executados)

O outro ( ClassLoader.getSystemClassLoader().loadClass("SomeClass"); ) irá:

  • use o carregador de classs “system” ( que é substituível )
  • não inicialize a class (digamos, se você usá-lo para carregar um driver JDBC, ele não será registrado e você não poderá usar o JDBC!)

Suponha que você esteja codificando um aplicativo da web que será executado em um contêiner como o Tomcat. O que o Tomcat faz é criar um carregador de classs para cada aplicativo da Web (para que ele possa descarregar os aplicativos Web mais tarde e liberar memory – você precisa de um carregador de classs dedicado para que isso funcione!). Nessa situação, você pode ver que ambas as chamadas produzirão resultados bem diferentes!

Para obter informações mais detalhadas (e autoritativas) sobre carregamento e boot de classs, consulte as seções 12.2 e 12.4 da (terceira) edição mais recente da Java Language Specification.

Class.forName() usa o classloader do chamador e inicializa a class (executa os inicializadores estáticos, etc.)

loadClass é um método ClassLoader , portanto, ele usa um carregador fornecido explicitamente e inicializa a class preguiçosamente (no primeiro uso).

Observe que há um Class.forName () que também recebe um ClassLoader .

Eles estão basicamente fazendo a mesma coisa. O ClassLoader usado pode ser diferente. Class.forName usa o ClassLoader obtido de this.getClass (). GetClassLoader () enquanto seu outro código especifica o uso do carregador de classs do sistema.

Na maioria dos aplicativos, esse será o mesmo carregador de classs, mas em ambientes mais complicados, como um aplicativo J2EE ou um applet, isso pode não ser o caso.

ClassLoader é uma class abstrata, no entanto, seu aplicativo é sempre carregado por um carregador de class, pode haver carregadores de class personalizados, como o carregador de class de rede ou qualquer outra fonte.

Por outro lado, Class em si representa classs e interfaces e a class Class possui uma function forName que usa o carregador de classs atual no qual seu aplicativo está sendo executado por padrão para carregar a class.

Aqui está a fonte para o Class.forName, que por sua vez chama o classloader de chamada.

 public static Class forName(String className) throws ClassNotFoundException { return forName0(className, true, ClassLoader.getCallerClassLoader()); } 

http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/ClassLoader.html

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Class.html#forName(java.lang.String )

Dica: carregador de classs Primordial http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html

  • Class.forName() carrega e inicializa a class. No subsistema do carregador de classs, ele executa todas as três fases, isto é, carregar, ligar e inicializar fases.

  • Comportamento ClassLoader.loadClass() , que atrasa a boot até que a class seja usada pela primeira vez. No subsistema do carregador de classs, ele executa apenas duas fases, isto é, as fases de carga e link.

Por exemplo:

 class MyClass { static { System.out.println("static block in MyClass"); } } public class TestCase1 { public static void main(String... args) throws Throwable { Class.forName("A"); } } //The above TestCase1 produce output: static block in MyClass public class TestCase2 { public static void main(String... args) throws Throwable { ClassLoader.getSystemClassLoader().loadClass("MyClass"); } } //The above TestCase2 not produce any output 

Eu amo o carregamento da class em java …

Isso realmente depende do contexto em que o aplicativo está sendo executado. Você obterá resultados diferentes se estiver usando-o em um contexto da web, em vez de apenas um programa de linha de comando.

Eu também tenho problemas, dependendo de como é o seu ClassPath e o que eu esperava acontecer.

Este artigo do JavaWorld explica muito sobre isso.