Класс.forName () vs ClassLoader.loadClass() - что использовать для динамической загрузки? [дубликат]
этот вопрос уже есть ответ здесь:
Разница между загрузкой класса с помощью ClassLoader и Class.forName
9 ответов
при динамической загрузке класса, когда это целесообразно использовать
Class.forName("SomeClass");
и когда я должен использовать
ClassLoader.getSystemClassLoader().loadClass("SomeClass");
или это два способа сделать то же самое?
6 ответов:
они совершенно разные!
как указано в документации для
Class.forName(String),возвращает объект класса, связанный с классом или интерфейсом с заданным строковым именем. Вызов этого метода эквивалентен:
Class.forName(className, true, currentLoader)(
trueздесь имеется в виду вы хотите инициализировать класс?)С другой стороны,
ClassLoader.loadClass(String):вызов этот метод эквивалентен вызову
loadClass(name, false).(здесь логическое значение не имеет ничего общего с инициализацией; но если вы проверите документацию loadClass(String, boolean), вы увидите, что все, что он делает, это загружает класс, а не инициализирует его).
первый (
Class.forName("SomeClass");) составит:
- используйте загрузчик классов, который загрузил класс, который вызывает этот код
- инициализировать класс (то есть все статические инициализаторы будут беги)
другую (
ClassLoader.getSystemClassLoader().loadClass("SomeClass");) составит:
- используйте загрузчик класса "system" (который переопределяется)
- не инициализировать класс (скажем, если вы используете его для загрузки драйвера JDBC, он не будет зарегистрирован, и вы не сможете использовать JDBC!)
предположим, что вы кодируете веб-приложение, которое будет выполняться на контейнере, таком как Tomcat. Tomcat создает загрузчик классов для каждого веб-приложения (так что он может выгрузить веб-приложения позже и освободить память - вам нужен специальный загрузчик классов для этой работы!). В этой ситуации вы можете видеть, что оба вызова дадут совершенно разные результаты!
для получения более подробной (и достоверной) информации о загрузке и инициализации класса, проверьте разделы 12.2 и 12.4 последней (3-й) версии спецификации языка Java.
Class.forName()использует загрузчик классов вызывающего объекта и инициализирует класс (запускает статические intitializers и т. д.)
loadClassэтоClassLoaderметод, поэтому он использует явно предоставленный загрузчик и лениво инициализирует класс (при первом использовании).обратите внимание, что есть класса.forName(), что также занимает
ClassLoader.
Они в основном делают то же самое. Однако используемый загрузчик классов может быть другим. Класс.forName использует загрузчик классов, который вы получаете от этого.getClass().getClassLoader () в то время как ваш другой код указывает на использование загрузчика системных классов.
в большинстве приложений это будет тот же загрузчик классов, но в более сложных средах, таких как приложение J2EE или апплет, это может быть не так.
ClassLoader является абстрактным классом, однако ваше приложение всегда загружается загрузчиком классов, могут быть пользовательские загрузчики классов, такие как сетевой загрузчик классов или любой другой источник.
С другой стороны, класс сам по себе представляет классы и интерфейсы, а класс class имеет функцию forName, которая использует текущий загрузчик классов, в котором ваше приложение работает по умолчанию для загрузки класса.
вот источник для класса.forName, который в свою очередь вызывает вызывающий загрузчик классов.
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)
подсказка: загрузчик первичных классов http://docs.oracle.com/javase/1.4.2/docs/guide/security/spec/security-spec.doc5.html
Class.forName()загрузить и инициализировать класс. В подсистеме загрузчика классов он выполняет все три фазы, т. е. фазы загрузки, соединения и инициализации.
ClassLoader.loadClass()поведение, которое задерживает инициализацию до тех пор, пока класс не будет использован в первый раз. В подсистеме загрузчика классов он выполняет только две фазы, т. е. фазы загрузки и соединения.например:
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
Я люблю загрузку классов в java...
Это действительно зависит от того, в каком контексте выполняется приложение. Вы получите разные результаты, если вы используете его из веб-контекста, а не просто программу командной строки.
Я также столкнулся с проблемами в зависимости от того, как выглядит Ваш ClassPath и что я ожидал, что произойдет.
этой JavaWorld статья объясняет многое об этом.
Comments