Какой ClassLoader я должен предоставить Proxy.newProxyInstance (...)? - PullRequest
9 голосов
/ 30 марта 2011

Я прочитал документацию, но я все еще не понимаю, какой загрузчик классов я должен предоставить в качестве аргумента. Я пробовал несколько вариантов, но это, похоже, не влияет на компиляцию или поведение прокси. Немного тревожно, что я могу передать что-либо в качестве аргумента загрузчика классов, включая null, и код все еще работает нормально. Может кто-нибудь объяснить это и сказать мне, какие ошибки могут возникнуть, если я приведу неверный аргумент для загрузчика классов? Я должен добавить, что у меня нет четкого интуитивного представления о том, что такое загрузчик классов, на Java или вообще.

1 Ответ

6 голосов
/ 30 марта 2011

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

Важной частью является следующее (в документации для getProxyClass()):

Все типы интерфейсов должны быть видны по имени через указанный загрузчик классов. Другими словами, для загрузчика классов cl и каждого интерфейса i следующее выражение должно быть истинным:

Class.forName(i.getName(), false, cl) == i

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

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

Зачем это нужно?

Вы можете представить это так:

  • Метод getProxyClass() создает (если он еще не существует) некоторый байт-код для нового класса, реализующего все методы всего вашего интерфейса (каждый из них просто перенаправляет вызов вашему InvocationHandler).
  • Затем он передает этот байт-код методу defineClass указанного вами загрузчика классов.
  • В этом байт-коде все ваши интерфейсы имеют ссылки по именам, и виртуальная машина теперь использует цитированный forName вызов для разрешения этих интерфейсов.

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

На самом деле для этого синтетического класса может не существовать фактического байт-кода, поскольку виртуальная машина может использовать здесь свою внутреннюю магию: -)

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