ClassLoading - очень сложный предмет. Модель безопасности ClassLoader и Java неразрывно связаны друг с другом. По сути, JVM загружает классы по требованию. При наличии иерархии загрузчиков классов JVM пытается разрешить класс как можно дальше вниз по цепочке. Короче говоря, если класс определен в загрузчике классов «boot» и в загрузчике классов, определенных приложением, он всегда будет использовать версию в загрузчике классов загрузки.
В загрузчике классов, таком как URLClassLoader, порядок поиска - это порядок, в котором вы сказали ему искать. По сути, массив URL-адресов, которые, как вы сказали, содержат классы, будет найден от первой записи до последней.
Когда определенный вами класс ссылается на другой класс, этот класс также разрешается с использованием того же алгоритма. Но здесь есть одна загвоздка: она только разрешает ее относительно того, где она была найдена. Давайте рассмотрим сценарий, в котором класс SomeCoolThing находится в загрузчике загрузчика классов, но зависит от SomeLameThing, который находится в определяемом приложением загрузчике классов. Процесс будет выглядеть так:
App-ClassLoader: resolveClass("SomeCoolThing")
parent->resolveClass("SomeCoolThing")
Boot-ClassLoader (the ultimate parent): resolveClass("SomeCoolThing")
SomeCoolThing needs SomeLameThing
resolveClass("SomeLameThing") // Can't find SomeLameThing!!!!
Несмотря на то, что SomeLameThing находится в загрузчике классов, где вы запросили SomeCoolThing, SomeCoolThing был разрешен в другом загрузчике классов. Этот другой загрузчик классов не знает дочерний загрузчик классов, и пытается разрешить его сам и завершается неудачей.
У меня была книга давным-давно, которая очень подробно рассказывала о Java ClassLoaders, и я рекомендую ее. Это Безопасность Java от O'Reilly Media . Он ответит на все вопросы, которые вы никогда не хотели знать, но все же должны знать, когда имеете дело с ClassLoaders и как они работают.