Так, каждый учебник Java говорит о том, как гибкий Java - так как он может загрузить классы во время выполнения. Просто почините строку и дайте ее Class.forName()
, и выгода ClassNotFoundException
и обработайте его. Так для теории.
Можно ли дать примеры того, как Вы использовали класс Java, загружающийся для достижения функции, которая иначе не была бы возможна или легка? Обратите внимание, что я не спрашиваю, "какие большие вещи мы могли сделать?" - я ищу реальные примеры, быть этим приложение с открытым исходным кодом или - если можно описать, это, не выделяя слишком много детализирует - закрытое приложение.
Править: Несомненно, VM загружает классы лениво, поскольку ему нужны они. Это - закулисная вещь, пока я уверен, что все классы, в которых я буду когда-либо нуждаться, там. Как я обрабатываю a ClassNotFoundException
? Предположим, что я записал ценность на десять страниц текста, и PrinterDriver
класс не может быть найден.
Плагины - первое, что приходит на ум. Загрузка класса Java делает ее очень простой по сравнению с такими языками, как C++.
Один момент, о котором вы, возможно, не знаете, это то, что любая виртуальная машина Java сильно зависит от внутренней загрузки класса. Каждый раз при обращении, скажем, к методу интерпретатора байткода, он проверяет, не загружен ли уже класс, которому принадлежит метод, и если нет, то загружает его, используя тот же самый механизм, что и Class.forName()
, перед тем как разрешить метод. Этот меканизм очень мощный, так как любое Java-приложение действительно действует как набор заменяемых компонентов, которые все динамически загружаются. Если ВМ хорошо написана, то она может, например, загружать классы через загрузчик пользовательских классов, который получает классы из сети, а не из обычных файлов.
Время загрузки классов зависит от реализации виртуальной машины, но большинство полагается на этот механизм поздней загрузки, который загружает класс при первой встрече ВМ с ним.
Контейнеры сервлетов, такие как Tomcat, читают ваш файл конфигурации war/webapp из WEB-INF/web.xml и загружают подклассы сервлетов/фильтров/и т.д., основываясь на значениях строк, которые вы поместили в XML-файл. Для подключения к базе данных, они вытаскивают имя класса для загрузки из вашей конфигурации, например, "com.mysql.jdbc.Driver" для MySQL.
См. Поддержка Oracle , например, в весенней основе . Только потому, что каркас предлагает конкретную поддержку Oracle, вы, вероятно, не хотите развертывать источник данных Oracle как зависимость для вашего E.G. MySQL проекты. Поэтому вы заряжаете драйверы Oracle, реча драйверов в объем экземпляра обработчика Лоб.
-121--1732671- Серверы приложений также сильно полагаются на классные загрузки
, чтобы выделить другой развернутый модуль. Например.
Благодаря магии классовых погрузчиков ...
Вот соответствующий фрагмент блога Сэма, в котором кратко рассказывается о политике кэширования.
http://blogs.msdn.com/samng/archive/2008/10/29/dynamic-in-c.aspx
DLR проверяет кэш на наличие данное действие уже привязано против текущего набора аргументов. В нашем примере мы бы сделали тип совпадение на основе 1, 2 и среды выполнения тип d. Если у нас попадание в кэш, затем мы возвращаем кэшированный результат. Если у нас нет попадания в кэш, то DLR проверяет, является ли приемник IDynamicObject. Эти парни по существу объекты, которые умеют заботиться о собственном обязательстве, например, как объекты COM IDispatch, реальные динамические объекты, такие как Ruby или Python, или некоторые объекты .NET, реализующие интерфейс IDynamicObject. Если это так любой из них, затем DLR выполняет вызов в IDO и просит его связать действия.
Обратите внимание, что результат вызова IDO для привязки - это дерево выражений, представляет результат привязки. Если это не IDO, то DLR вызовы в языковую привязку (в нашем случай, связующая среда выполнения C #) для связывания операция. Связующая среда выполнения C # свяжет действие и вернет дерево выражения, представляющее результат привязки. Один раз шаг 2 или 3 произошло, в результате дерево выражения объединено с механизм кэширования, чтобы любой последующие вызовы могут выполняться для кэш вместо быть отскока.
Однако Сэм не упоминает, что именно такая политика пропуска кэша. Существуют две основные политики пропуска кэша: (1) запуск промаха кэша при изменении типов аргументов, (2) запуск промаха кэша при изменении идентификаторов аргументов.
Очевидно, что первый гораздо более эффективен; отрабатывать, когда мы можем кэшировать только на основе типа, сложно. Детальная экзегеза того, как вся эта логика работает, займет довольно много времени; Надеюсь, я или Крис или Сэм сделаем запись в блоге на нем в один из этих дней.
-121--3186065-Пользователи, регулярные выражения НЕЛЬЗЯ использовать для синтаксического анализа нерегулярных языков. Нерегулярные языки - это языки, для интерпретации которых требуется состояние (т.е. запоминание количества открытых скобок).
Все вышеперечисленные ответы потерпят неудачу на этой последовательности: «ABC (привет (мир) как ты)».
Прочитайте сообщение Джеффа Этвуда «Parsing Html The Cthulhu Way: https://blog.codinghorror.com/parsing-html-the-cthulhu-way/ », а затем используйте либо побочный синтаксический анализатор (циклический анализ символов в последовательности, проверьте, является ли символ скобкой или нет, поддерживайте стек), либо используйте lexer/parser, способный анализировать язык без контекста
Также смотрите эту статью википедии о «языке правильно соответствующих скобок:» https://en.wikipedia.org/wiki/Dyck_language
-121--973788-Можно использовать метод Class:: forName, если класс находится в пути к классу. Однако если необходимо указать путь вместе с именем класса, например, c :\document\xyz.class, необходимо использовать класс URLClassLoader.
Механизм classloader Java является мощным, поскольку предоставляет абстракционную точку именно в той точке, где загружен код, что позволяет выполнять следующие действия:
На точке изменения кода во время загрузки, есть мир интересных вещей, которые вы можете сделать, чтобы переделать ваш код - AOP, профилирование, трассировка, изменения поведения и т.д. В Terracotta мы полагались на абстракцию classloader, чтобы динамически загрузить класс, затем перехватить весь доступ к полям и динамически добавить возможность загрузки состояния из того же объекта на удаленном узле в кластере позже. Классные вещи.
-121--1732673-Использование динамической загрузки класса также очень полезно для загрузки файлов конфигурации, как упоминает Тило. В более общем случае динамическая загрузка класса во многих ситуациях может создать хороший уровень абстракции файловой системы, упрощая настройку записи и чувствительный к конфигурации код. Просто убедитесь, что нужный ресурс находится на пути к классам, и загрузите его как InputStream.
Кроме того, с помощью пользовательского обработчика протокола в Java можно получить доступ к предметам на пути к классам по URL. Это не является преимуществом, характерным для динамической загрузки классов, но демонстрирует, как можно получить доступ к ресурсам пути к классам через тот же API, что и к другим ресурсам (даже удаленным). http://java.sun.com/developer/onlineTraining/protocolhandlers/
-121--1732668-Любая рамка, основанный на конфигурации (стойки, jsf, пружина, спящий режим и т.д.), использует этот механизм. Любой продукт, основанный на архитектуре плагина, также использует эту функцию.
Использование динамической загрузки классов также очень полезно для загрузки файлов конфигурации, как упоминает Тило. В более общем плане, загрузка динамического класса может во многих ситуациях создать хороший уровень абстракции файловой системы, упрощая написание предпочтений и кода, чувствительного к конфигурации. Просто убедитесь, что нужный вам ресурс находится в пути к классам, и загрузите его как InputStream.
Кроме того, с помощью специального обработчика протокола в Java можно получить доступ к элементам в пути к классам через URL. Это не является преимуществом, характерным для динамической загрузки классов, но демонстрирует, как к ресурсам пути к классам можно получить доступ через тот же API, что и к другим ресурсам (даже удаленным). http://java.sun.com/developer/onlineTraining/protocolhandlers/
Реальный пример (как указано в вашем вопросе), проприетарное приложение (как явно разрешено вашим вопросом) ...
При запуске клиентское программное обеспечение связывается с нашим сервером (-ами) и говорит: «Реализация по умолчанию У меня есть панель интерфейса Foo (потому что на самом деле каждая версия 1.03, например, использует Foo), у вас есть лучший? " Если тем временем мы написали лучшую реализацию, мы ответим: «Ага, Bar старый, используйте Buz, это лучше».
Затем на стороне клиента используется загрузчик классов для загрузки последней реализации.
Это слишком упрощенно, но это реальный пример. Это не совсем похоже на упомянутый пример JRL: где устаревшие классы автоматически заменяются более новыми.
См. Поддержка обработки Oracle в пружинной структуре. Только потому, что каркас предлагает конкретную поддержку Oracle, вы, вероятно, не хотите развертывать источник данных Oracle как зависимость для вашего E.G. MySQL проекты. Поэтому вы заряжаете драйверы Oracle, реча драйверов в объем экземпляра обработчика Лоб.
Сообщения поступают из App Store, поэтому изменить текст невозможно. Ты должен пойти в другую сторону. Когда пользователь нажимает кнопку или ячейку таблицы, связанную с заблокированной функцией, отображается сообщение с просьбой купить ее. Если он/она подтвердит, появится сообщение App Store.
-121--4690782- Python не имеет встроенного эквивалента sscanf
, и в большинстве случаев имеет гораздо больше смысла анализировать входные данные, работая непосредственно с последовательностью, используя regexps или инструмент синтаксического анализа.
Возможно, в основном полезно для перевода C, люди внедрили sscanf
, например, в этом модуле: http://hkn.eecs.berkeley.edu/~dyoo/python/scanf/
В данном конкретном случае, если вы просто хотите разделить данные на основе нескольких разделенных символов, re.split
действительно является правильным инструментом.
Я использую его при создании готового приложения, которое должно быть адаптировано мной или клиентом для удовлетворения конкретных требований клиента.
Я помню, как создавал загрузчик классов для удаленной загрузки классов. Приложение работало на одном узле, а классы хранились на другом узле.
А также, настроив загрузчик классов, вы можете преобразовывать классы по мере их загрузки. Это используется некоторыми фреймворками ORM, а также некоторыми фреймворками АОП.
Я думаю, что Junit может также использовать много функций отражения, чтобы сделать тестовые рамки универсальными.
Классический загрузчик также используется для неклассных ресурсов. Файлы конфигурации приходят на ум. Поскольку есть четко определенный порядок поиска, легко запускать свой собственный «log4j.xml» или "hibernate.properties", и приложение найдет и использует его.
Это может быть чрезвычайно полезно в ситуациях, когда вы используете API, а разработчики API фактически устарели некоторые классы из одной версии в другую (например, Contacts в Android).
Без рефлексии и динамической загрузки классов, основанной на имени строки, в данном случае было бы невозможно запустить одну и ту же программу на обеих версиях платформы, не получив класс, не найденный исключение во время выполнения. Но при этом одна и та же программа была немного подкорректирована и затем могла бы выполняться на обеих платформах.
Я уверен, что загрузка плагина в Java во многом зависит от этого.
Приложение проверяет именованные функции и выполняет их
Eclipse на самом деле использует это для плагинов
Ключевая идея заключается в выполнении кода, который не был запланирован во время разработки.
Ну, я использовал его для динамически загрузки драйверов JDBC в приложение J2EE. Weatheher Это могло быть сделано лучшим способом, я понятия не имею.
В то время было просто проще сделать forname ()
.
«Плагин» и это большое слово.
В основном вы можете загрузить класс, который вы не знаете, когда или не существует, когда вы пишете и компилируете свою программу.
Например, если вы хотите, чтобы программа выполнить проверку орфографии, вы можете написать интерфейс ScreenChecker
, затем загрузите класс из файла конфигурации, который реализует интерфейс ScreenChecker
. После этого вы можете написать любой соревнования и установить в файл конфигурации фактическое имя файла. Таким образом, ваша программа не должна знать, какой класс сделает проверку орфографии.
Драйвер БД, плагин Eclipse, язык скрипта, методы криптографии все делают таким образом, поскольку оригинальный писатель не знает (и в некоторых случаях не имеет идеи), какой класс на самом деле будет использоваться.
Надеюсь, это поможет.
Механизм Java classloader является мощным, так как он предоставляет точку абстракции именно в точке загрузки кода, что позволяет делать такие вещи:
С точки зрения модификации кода во время загрузки, есть целый мир интересных вещей, которые вы можете сделать для ремиксов вашего кода - AOP, профилирование, трассировка, модификация поведения и т.д. В Terracotta мы полагались на абстракцию classloader для динамической загрузки класса, затем перехватывали все обращения к полям и динамически добавляли возможность загрузки состояния с того же самого объекта на удаленном узле в кластере позже. Классная вещь.
JDBC API - отличный тому пример. Таким образом, вы можете настроить драйвер JDBC извне, например, в файле свойств:
driver = com.dbvendor.jdbc.Driver url = jdbc:dbvendor://localhost/dbname username = stackoverflow password = youneverguess
.. который вы можете использовать как:
Properties properties = new Properties();
properties.load(Thread.currentThread().getResourceAsStream("jdbc.properties"));
String driver = properties.getProperty("driver");
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
Class.forName(driver);
Connection connection = DriverManager.getConnection(url, username, password);
Каждая реализация драйвера JDBC в основном регистрируется в DriverManager
внутри ] static
блок инициализатора. Это именно тот, который выполняется во время Class # forName ()
.
package com.dbvendor.jdbc;
public class Driver implements java.sql.Driver {
static {
java.sql.DriverManager.registerDriver(new Driver());
}
private Driver() {
// ...
}
public boolean acceptsURL(String url) {
return url.startsWith("jdbc:dbvendor");
}
}
Поскольку DriverManager
примерно выглядит так (на самом деле он использует старомодный Vector
)
private static final Set<Driver> drivers = new HashSet<Driver>();
public static void registerDriver(Driver driver) {
drivers.add(driver);
}
public static Connection getConnection(String url, String username, String password) throws SQLException {
for (Driver driver : drivers) {
if (driver.acceptsURL(url)) {
return driver.connect(url, username, password);
}
}
throw new SQLException("No suitable driver");
}
... вы можете получить от него соединение без необходимости создать экземпляр самого драйвера!
Таким образом, код JDBC становится легко переносимым. Вы можете изменить БД или распространить код среди пользователей с разными БД без необходимости изменять / взламывать / перестраивать сам код.
Этот подход использует не только JDBC, но и другие API, такие как Servlet API, ORM, такие как Hibernate / JPA, фреймворки внедрения зависимостей и т.д. . Все это делает код более портативным и легко подключаемым.