Модель делегирования класса Java ClassLoader?

При вызове loadClass() на ClassLoader, сначала проверяет ClassLoader, был ли класс загружен, или делает это немедленно делегируйте эту проверку своему родителю ClassLoader?

Java API говорит:

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

Но есть отдельная глава о загрузчике классов в книге Java Reflection in Action, в которой говорится:

Загрузчик класса вызывает findLoadedClass, чтобы проверить, был ли уже загружен класс. Если загрузчик классов не находит загруженный класс, вызывает loadClass на загрузчике родительского класса.

Что правильно?

Ответ 1

Правильная реализация загрузчика классов будет:

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

Реализация класса ClassLoader.loadClass по умолчанию имеет значение:

protected synchronized Class<?> loadClass(String name, boolean resolve) {
  // First, check if this class loader has directly defined the class or if the
  // JVM has initiated the class load with this class loader.
  Class<?> result = findLoadedClass(name);
  if (result == null) {
    try {
      // Next, delegate to the parent.
      result = getParent().loadClass(name);
    } catch (ClassNotFoundException ex) {
      // Finally, search locally if the parent could not find the class.
      result = findClass(ex);
    }
  }
  // As a remnant of J2SE 1.0.2, link the class if a subclass of the class
  // loader class requested it (the JVM never calls the method,
  // loadClass(String) passes false, and the protected access modifier prevents
  // callers from passing true).
  if (resolve) {
    resolveClass(result);
  }
  return result;
}

Некоторые реализации загрузчика классов передают другим загрузчикам без родительского класса (OSGi, например, делегирует граф загрузчиков классов в зависимости от пакета), а некоторые реализации загрузчика классов будут искать классы в локальном пути класса перед передачей.

Ответ 2

API Java корректен.

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

Из Механизм загрузки Java-классов -

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

Ответ 3

Оба утверждения не являются полностью взаимоисключающими. Класс будет существовать только в текущем наборе классов ClassLoader загруженных классов, если родительский ClassLoader ранее не смог найти класс. Итак,

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

Это не предотвращает короткое замыкание, если он знает, что его родитель не может найти класс, но он может (как показано ранее загрузкой класса)

Ответ 4

Это в основном, как это работает. Вы печатаете

Foo f = new Foo();

В этот момент загрузчик классов определит, была ли загружена Foo(), а именно ее биты в памяти /perm gen. Если он был загружен, используйте его. В противном случае делегируйте его загрузчику родительского класса, чтобы попытаться разрешить класс. Биты этого класса считываются с диска, а затем загружаются в память. В следующем new Foo() класс будет теперь найден в памяти/загружен.

Ответ 5

Чтобы согласиться с ответом Sri, он всегда будет передан родительскому элементу, и api будет правильным. Если вы играете с загрузкой классов, это может сделать вещи немного сложными, чтобы поправиться или добиться эффекта, которым вы пользуетесь. Я хотел бы предложить запустить jvm с минимальным пути classpath и затем загружать все классы, используя ваш пользовательский загрузчик классов. Самый простой способ сделать это - использовать URLClassloader или составной объект, обертывающий URLClassloader, чтобы вы могли отслеживать, какие классы загружаются и когда.

Также стоит иметь в виду, что класс A, загруженный загрузчиком классов C!= class A, загружаемым загрузчиком классов C, если C и D не являются частью той же иерархии loadload-parent-parent-child.

Ответ 6

В этом контексте следует отметить еще одну проблему. В документе API говорится:

Методы и конструкторы объекты, созданные загрузчиком классов, могут ссылку на другие классы. Определить упомянутый класс (ы), Java виртуальная машина вызывает loadClass метод загрузчика классов, который изначально созданный класс.

Значение того, что сети ссылочных классов загружаются одним и тем же загрузчиком классов.