Подтвердить что ты не робот

Java: разница между Class.forName и ClassLoader.loadClass

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

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

и

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

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

Спасибо заранее.

4b9b3361

Ответ 1

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, а логический параметр определяет, должен ли класс инициализироваться при его загрузке или нет.

Ответ 2

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

  • Class.forName связывает класс w/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

Когда вы используете 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 также может использоваться со строками, представляющими примитивные типы или классы массивов.

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

Ответ 4

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

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

Ответ 5

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