ClassLoader в Java - PullRequest
       56

ClassLoader в Java

0 голосов
/ 19 ноября 2018

Я играл с загрузчиками классов в Java и обнаружил следующее поведение.Я мог бы логически обосновать это, но я не уверен, что то, что я предполагаю, полностью верно.Я хотел бы знать более формальное объяснение этого поведения.

Что я пытался?Итак, у меня был следующий код:

URL[] classURLs = {new URL("file://C:/Users/HP/IdeaProjects/test/out/production/test/")};
URLClassLoader urlClassLoader = new URLClassLoader(classURLs, null);
Class<?> personClass = urlClassLoader.loadClass("com.test.Person");

// the following line will give a ClassCastException
Person p = (Person) personClass.getDeclaredConstructor().newInstance();

Теперь последняя строка дает мне ClassCastException.

Мои рассуждения (предположение) о том, почему я получаюa ClassCastException: загрузчик классов personClass равен urlClassLoader, тогда как загрузчик классов Person на самом деле является загрузчиком классов приложений или системным загрузчиком классов (, пожалуйста, исправьте меня, если я ошибаюсь ).Эти загрузчики классов не совпадают, и я получаю ClassCastException.(Я здесь предполагаю, что когда приведение типов выполняется проверка на загрузчиках классов)

Так что теперь я продолжаю исследовать и изменять конструкцию URLClassLoader следующим образом:

URLClassLoader urlClassLoader = new URLClassLoader(classURLs, Main.class.getClassLoader());

Здесь Main является классом включения.Вышеуказанная строка спасает меня от ClassCastException.

Мое рассуждение ( думаю ) об этом: Как и сейчас, urlClassLoader имеет загрузчик класса приложения в качестве родителя (этот загрузчик класса приложения такой же, который используется для загрузки Person класса), при попытке привести Java проверяет, совпадают ли загрузчики классов, и эта проверка продолжается с родителем urlClassLoader, после того, как на один шаг вверх совпадение с загрузчиками классов и ClassCastException нет.

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

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

Я видел это ссылка , но это не дает подробностей, которые я просил.

Ответы [ 2 ]

0 голосов
/ 19 ноября 2018

Официальная документация о поведении, которое вы наблюдаете, содержится в ClassLoader # loadClass () документации:

Загружает класс с указанным двоичным именем. Реализация по умолчанию этого метода ищет классы в следующем порядке:

  1. Вызвать findLoadedClass (String), чтобы проверить, был ли класс уже загружен.

  2. Вызвать метод loadClass в загрузчике родительского класса. Если родительский объект имеет значение null, вместо него используется встроенный в виртуальную машину загрузчик классов.

  3. Вызовите метод findClass (String), чтобы найти класс.

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

Итак, если вы установите загрузчик родительского класса, эта строка:

Class<?> personClass = urlClassLoader.loadClass("com.test.Person");

ведет себя так же, как

Class<?> personClass = Main.class.getClassLoader().loadClass("com.test.Person");

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

0 голосов
/ 19 ноября 2018

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

Удалите библиотеку из вашего classpath, и вы не получите эту ошибку, однако вы также потеряете доступ к объекту Person.

Это все еще там, когда вы загружаете его, но способ получить доступ к нему будет через Reflection, и вам нужно будет сохранить объект «Персона» как «Объект».

...