Это абстрактный класс, ответственный за загрузку типов. По имени класса или интерфейса он находит и загружает в память данные, которые составляют определение типа. Обычно для этого используется простое правило: название типа преобразуется в название class-файла, из которого и считывается вся необходимая информация.
Каждый объект Class содержит ссылку на объект ClassLoader, с помощью которого он был загружен.
Для добавления альтернативного способа загрузки классов можно реализовать свой загрузчик, унаследовав его от ClassLoader. Например, описание класса может загружаться через сетевое соединение. Метод defineClass() преобразует массив байт в экземпляр класса Class. С помощью метода newInstance() могут быть получены экземпляры такого класса. В результате загруженный класс становится полноценной частью исполняемого Java-предложения.
Для иллюстрации приведем пример, как может выглядеть простая реализация загрузчика классов, использующего сетевое соединение:
class NetworkClassLoader extends ClassLoader { String host; int port; public NetworkClassLoader(String host, int port) { this.host = host; this.port = port; } public Class findClass(String className) { byte[] bytes = loadClassData(className); return defineClass(className, bytes, 0, bytes.length); } private byte[] loadClassData( String className) { byte[] result = null; // open connection, load the class data return result; } }
В этом примере только показано, что наследник загрузчика классов должен определить и реализовать методы findClass() и loadClassData() для загрузки описания класса. Когда описание получено, массив байт передается в метод defineClass() для создания экземпляра Class. Для простоты в примере приведен только шаблонный код, без реализации получения байт из сетевого соединения.
Для получения экземпляров классов, загруженных с помощью этого загрузчика, можно воспользоваться методом loadClass():
try { ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass( "Main").newInstance(); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); }
Если такой класс не будет найден, будет брошено исключение ClassNotFoundException, если класс будет найден, но произойдет какая-либо ошибка при создании объекта этого класса – будет брошено исключение InstantiationException, и, наконец, если у вызывающего потока не имеется соответствующих прав для создания экземпляров этого класса (что проверяется менеджером безопасности), будет брошено исключение IllegalAccessException.