Java: разница между Class.forName и ClassLoader.loadClass - PullRequest
40 голосов
/ 01 декабря 2011

Недавно наткнулся на какой-то код, который заставил меня задуматься. В чем разница между:

Class theClass = Class.forName("SomeImpl");
SomeImpl impl = (SomeImpl)theClass.newInstance();

и

Class theClass = ClassLoader.loadClass("SomeImpl");
SomeImpl impl = (SomeImpl)theClass.newInstance();

Они являются синонимами? Является ли одно предпочтительнее другого в определенных обстоятельствах? Как можно и нельзя использовать эти два метода?

Заранее спасибо.

Ответы [ 5 ]

18 голосов
/ 01 декабря 2011

Class.forName () всегда будет использовать ClassLoader вызывающей стороны, тогда как ClassLoader.loadClass () может указывать другой ClassLoader.Я считаю, что Class.forName также инициализирует загруженный класс, в то время как подход ClassLoader.loadClass () не делает это сразу (он не инициализируется, пока не будет использован в первый раз).статья при поиске, чтобы подтвердить мое резюме поведения инициализации.Похоже, здесь содержится большая часть информации, которую вы ищете:

http://www.javaworld.com/javaworld/javaqa/2003-03/01-qa-0314-forname.html

Это довольно крутое использование, хотя я никогда не использовал его раньше:

Class.forName(String, boolean, ClassLoader)

Позволяет указать ClassLoader, а логический параметр определяет, должен ли класс быть инициализирован при загрузке или нет.

11 голосов
/ 01 декабря 2011

Ответ Шона более или менее правильный, за исключением нескольких пропусков / небольших ошибок:

  • Class.forName связывает класс с ClassLoader (независимо от того, загружает ли его любой другой родительский объект по-настоящему), следовательно, ClassLoader.findLoadedClass успешно в следующий раз.Это очень, очень важный момент, большинство ClassLoader будет пытаться Class c = findLoadedClass(name); if (c!=null) return c; в качестве первых операторов, минуя всю часть поиска / поиска.Непосредственный вызов ClassLoader.load не добавит класс к загруженным.

Случай имеет значение, когда загружается через структуру графа, похожую на ClassLoader, т.е. не использует родительский элемент только для поиска вначале.

  • Инициализация класса выполняется в loadClass класса ClassLoader с таким кодом: if (resolve) resolveClass(c);, и ClassLoader может фактически пропустить его разрешение, как будто это не рекомендуется, но возможно.

Что можно и нельзя делать с использованием этих двух методов?

Если у вас нет очень четкого представления, почему вы хотите ClassLoader.loadClass(String), не используйте его напрямую.Во всех других случаях всегда полагайтесь на Class.forName(name, true, classLoader).

Общая загрузка класса находится рядом с искусством и не может быть охвачена простым ответом (не шутка с художественной частью)

3 голосов
/ 01 декабря 2011

Когда вы используете Class.forName("SomeImpl"), вы получаете класс через текущий загрузчик классов (т.е. загрузчик класса, в котором вы вызываете метод).Это также инициализирует класс.По сути, это то же самое, что и вызов Class.forName("SomeImpl", true, currentLoader), где currentLoader будет загрузчиком классов вызывающей стороны.Смотрите подробности здесь .

Второй метод требует, чтобы загрузчик классов был выбран первым.Не пишите это как ClassLoader.loadClass("SomeImpl"), так как это не статический метод.Вам потребуется что-то вроде

final ClassLoader cl = this.getClass().getClassLoader();
Class theClass = cl.loadClass("SomeImpl");

Помните, что подклассы ClassLoader должны переопределять метод findClass вместо loadClass.Это то же самое, что вызов (защищенного) метода loadClass("SomeImpl", false), где второй аргумент указывает, следует ли выполнять связывание или нет.

Существуют более тонкие различия ... Метод loadClass ожидает двоичный файлимя класса, как указано в спецификации языка Java, в то время как forName может также использоваться со строками, представляющими примитивные типы или классы массивов.

Overal, лучше использовать Class.forName, если необходимо указать конкретный загрузчик классов идолжен ли он быть инициализирован или нет, тогда пусть реализация выяснит все остальное.Непосредственное использование загрузчиков классов полезно для поиска ресурсов в банке или на пути к классам.

1 голос
/ 22 июня 2013

Эта строка не будет компилироваться:

Class theClass = ClassLoader.loadClass("SomeImpl");

потому что loadClass не является статическим методом ClassLoader.

Чтобы решить эту проблему, создайте объект ClassLoader одним из трех возможных способов:

ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
ClassLoader classLoader = Main.class.getClassLoader();      // Assuming in class Main
ClassLoader classLoader = getClass().getClassLoader();      // works in any class

затем позвоните:

Class theClass = classLoader.loadClass("SomeImpl");

-dbednar

0 голосов
/ 20 января 2017

Метод loadClass() нельзя вызвать как static.Создайте подкласс для ClassLoader и используйте некоторые другие другие методы для выполнения операций.Можно создать собственный загрузчик классов, расширив класс ClassLoader.В функциональном отношении оба способа одинаковы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...