java.lang.Class, вероятно, является одним из самых известных классов Java, и если вы пишете приложения или фреймворки, вы, вероятно, сталкивались с ним много раз, либо поверхностно (getClass ()), либо более подробно (отражение, загрузчики классов и т. д.) ,
java.lang.Class также является очень специальным классом в экосистеме Java, и поэтому он ограничен некоторыми весьма специфическими способами. Одна из них заключается в том, что разработчики не могут сами создать новый объект Class (у класса нет открытого конструктора), только JVM может создавать объекты Class. Когда вы пишете код Java и хотите реализовать некоторые из этих объектов, ваши возможности довольно ограничены:
- Создайте загрузчик классов и используйте метод defineClass (). Загрузчики классов являются сложными и требуют много глубоких знаний о JVM, чтобы правильно понять, а defineClass () также требует от вас предоставить байт-код для класса, который вы хотите создать.
- Генерация кода. Это более традиционный подход. Этого проще достичь некоторыми способами (все, что вам нужно сделать, это сгенерировать источник нужного вам класса), а в других — сложнее (вам нужно заразить вашу сборку знаниями об этих сгенерированных классах и научить ее объединять их с ваше приложение).
- Вы можете использовать динамические прокси. Динамические прокси точно не материализуют новые классы, поэтому они не должны быть частью этого списка, но я подумал, что упомяну их, поскольку они могут быть довольно мощным решением общей проблемы генерации новых типов в программах Java ( обратите внимание, что этот подход менее типизирован, чем два других).
Несмотря на свои недостатки, все эти подходы с большим успехом использовались различными средами Java, и эти методы сыграли большую роль в превращении Java в такую сильную платформу, которая остается способной решать большинство инженерных проблем, возникающих в наши дни.
Сказав это, что мы можем сделать, чтобы улучшить эти подходы?
Представьте себе новый тип под названием IType. На самом деле это интерфейс, поэтому любой класс может его реализовать. Давайте теперь предположим, что везде в JVM, где ожидается Class, мы можем вместо этого использовать IType (очевидно, мы заставим Class реализовать IType). IType — это новое представление класса внутри JVM, и любой объект, который его реализует, может быть передан вместо Class.
Очевидно, что IType должен иметь возможность выполнять все операции, которые может выполнять Class, среди которых:
- Вернуть информацию о его имени, пакете, родительских типах, вложенных типах и т. Д.
- Реагируйте на стандартные операции самоанализа, такие как возврат списка методов, которые он предоставляет.
Очевидно, что методы, возвращаемые IType, также должны быть абстрагированы, поэтому вместо возврата java.lang.reflect.Method мы возвращаем новый тип IMethod. Мы предъявляем те же требования к IMethod, что и для Method: интроспекция много работает с этими объектами и, что более важно, нам нужно реализовать invoke (). Если объект, который мы возвращаем, является экземпляром метода, реализация invoke () тривиальна (просто делегируйте его базовому объекту метода).
Но что произойдет, если вместо возврата стандартных объектов Java Class и Method мы решим вернуть что-то другое?
На самом деле, что могут быть эти другие объекты?
Как оказалось, ничего. Они могут представлять файлы: .xml, но как насчет .xsd или .properties? Или как насчет источников на другом языке? Может быть .groovy, .bash или .scala? Думая дальше нестандартно, как насчет концепций, которые не являются файлами, такими как таблицы базы данных? Или виртуальные файлы, или файлы, присутствующие в удаленной файловой системе? Как насчет конечной точки сетевого подключения (и нам все равно, что питает эту конечную точку)? Мы также можем принять решение представить результаты API REST, AJAX или JSON.
Эта новая система типов не заботится о том, что на самом деле лежит в основе концепции, все, что ей нужно — это набор ITypes (и несколько других деталей, которые я подчеркиваю), и она представит эти типы JVM, как если бы они были подлинные занятия. Поддерживаются ли они байт-кодом Java или какой-либо другой логикой, не имеет значения.
Вот быстрый пример того, как может выглядеть такой тип.
Давайте предположим, что мы хотим сделать файлы свойств Java первоклассными гражданами в этой новой системе типов (это глупый пример, поскольку простая хеш-таблица достаточно хороша, но это только для иллюстрации). Идея состоит в том, что всякий раз, когда мы встречаем файл с именем «foo.properties», мы создаем класс с именем FooProperties, и каждый ключ / значение, найденный в этом файле, будет представлен как получатель. Например, загрузка этого файла в этой новой системе типов:
позволит вам написать следующий код:
Реализация соответствующих интерфейсов IType и IMethod довольно проста в этом случае, но это должно дать вам представление о гибкости такой системы типов.
То, что я только что описал, — это в основном система открытого типа Госу . Gosu — это не просто «еще один язык JVM», он также обеспечивает открытость типов, которая позволяет вам материализовать практически все как настоящий тип Gosu. После того, как вы описали свой тип, он становится частью вашей программы Gosu и, как таковой, получает те же привилегии, что и любой другой тип (например, он может использоваться IDE для завершения, просмотра, рефакторинга и т. Д.).
Сказав это, давайте теперь рассмотрим вещи в перспективе:
- Проектирование метакласса в Java является преднамеренным: он был задуман таким образом по соображениям безопасности, идея в том, что типы, материализуемые в вашем процессе JVM, должны проходить через очень специфический конвейер, чтобы его можно было проверять и проверять на наличие злокачественных атак. Я предполагаю, что эта система чрезвычайно параноидальна, потому что Java изначально была основана на апплетах, но мне интересно, сохраняются ли такие проблемы сегодня.
- Хотя система открытого типа Gosu элегантна, она в основном просто избавляет вас от этапа генерации кода.
Я предполагаю, что не все будут думать, что преимущества такой системы типов перевешивают недостатки, но я хотел бы услышать некоторые отзывы о том, считаете ли вы, что будущие языки должны предоставлять доступ к такой функциональности, или это просто хорошая теоретическая игрушка, практичность которой сомнительна.
Вот некоторые дополнительные материалы о системе открытых типов Gosu: