Подтвердить что ты не робот

Возможно ли статическое метапрограммирование в Java?

Я поклонник статического метапрограммирования в С++. Я знаю, что Java теперь имеет дженерики. Означает ли это, что статическое метапрограммирование (т.е. Выполнение программы компиляции) возможно в Java? Если да, можете ли кто-нибудь рекомендовать какие-либо хорошие ресурсы, где можно узнать больше об этом?

4b9b3361

Ответ 1

Нет, это невозможно. Дженерики не такие мощные, как шаблоны. Например, аргумент шаблона может быть определяемым пользователем типом, примитивным типом или значением; но общий аргумент шаблона может быть только Object или его подтип.

Изменить: это старый ответ; с 2011 года у нас есть Java 7, в которой есть аннотации, которые можно использовать для таких обманщиков.

Ответ 2

Посмотрите Clojure. Это LISP с макросами (метапрограммирование), которые работают на JVM и очень совместимы с Java.

Ответ 3

Что вы подразумеваете под "статическим метапрограммированием"? Да, метапрограммирование шаблона С++ невозможно в Java, но оно предлагает другие методы, гораздо более мощные, чем те, что из С++:

  • отражение
  • аспектно-ориентированное программирование (@AspectJ)
  • манипуляция bytecode (Javassist, ObjectWeb ASM, Java-агенты)
  • генерация кода (инструмент обработки аннотации, механизмы шаблонов, такие как скорость)
  • Абстрактные синтаксические манипуляции с деревьями (API, предоставляемые популярными IDE)
  • возможность запуска компилятора Java и использование скомпилированного кода даже во время выполнения

Нет лучшего метода: каждый из этих методов имеет свои сильные и слабые стороны. Из-за гибкости JVM все эти методы в Java могут использоваться как во время компиляции, так и во время выполнения.

Ответ 4

Нет. Более того, общие типы стираются до их верхней границы компилятором, поэтому вы не можете создать новый экземпляр родового типа T во время выполнения.

Лучший способ метапрограммирования в Java - обходить стирание типа и руку в объекте Class<T> вашего типа T. Тем не менее, это всего лишь взлом.

Ответ 5

Нет, генераторы в Java - это просто способ избежать кастования объекта.

Ответ 6

Если вам нужна мощная логика компиляции для Java, один из способов сделать это с каким-то генератором кода. Поскольку, как отмечали другие плакаты, язык Java не предоставляет никаких функций, подходящих для выполнения логики времени компиляции, это может быть вашим лучшим вариантом (если у вас действительно есть потребность в логике времени компиляции). Как только вы исчерпали другие возможности, и вы уверены, что хотите генерировать код, вам может быть интересен мой проект с открытым исходным кодом Rjava, доступный по адресу:

http://www.github.com/blak3mill3r

Это библиотека генерации кода Java, написанная на Ruby, которую я написал, чтобы автоматически создавать интерфейсы Google Web Toolkit для приложений Ruby on Rails. Это оказалось весьма удобным для этого.

Как предупреждение, может быть очень сложно отладить код Rjava, Rjava не делает много проверки, он просто предполагает, что вы знаете, что делаете. Это в значительной степени состояние статического метапрограммирования в любом случае. Я бы сказал, что это значительно проще отлаживать, чем что-либо, что нетривиально сделано с С++ TMP, и можно использовать его для тех же самых вещей.

В любом случае, если вы подумывали написать программу, которая выводит исходный код Java, остановитесь прямо сейчас и проверьте Rjava. Возможно, он не будет делать то, что вы хотите, но он лицензирован MIT, поэтому не стесняйтесь улучшать его, обжарить или продавать его своей бабушке. Я был бы рад, если бы другие разработчики, имеющие опыт разработки общих программ, прокомментировали дизайн.

Ответ 7

Краткий ответ

Этому вопросу уже более 10 лет, но мне все еще не хватает одного ответа на этот вопрос. И это: да, но не из-за дженериков и примечаний, совершенно аналогичных C++.

Начиная с Java 6, у нас есть подключаемый API для обработки аннотаций. Статическое метапрограммирование (как вы уже указали в своем вопросе)

выполнение программы во время компиляции

Если вы знаете о метапрограммировании, то вы также знаете, что это не совсем так, но ради простоты мы это сделаем. Пожалуйста, посмотрите здесь, если вы хотите узнать больше о метапрограммировании в целом.

Подключаемый API для обработки аннотаций вызывается компилятором сразу после чтения файлов .java, но до того, как компилятор записывает байт-код в файлы .class. (У меня был один источник для этого, но я больше не могу его найти... может быть, кто-то может помочь мне здесь?).

Это позволяет вам делать логику во время компиляции с чистым java-кодом. Однако мир, в котором вы кодируете, совсем другой. Не особенно плохо или что-то, просто другое. Классы, которые вы анализируете, еще не существуют, и вы работаете с метаданными классов. Но компилятор запускается в JVM, что означает, что вы также можете создавать классы и программы как обычно. Но, кроме того, вы можете анализировать универсальные шаблоны, потому что наш процессор аннотаций называется до стирания типа.

Основная суть статического метапрограммирования в Java заключается в том, что вы предоставляете метаданные (в виде аннотаций), и процессор сможет найти все аннотированные классы для их обработки. Пример (более простой) можно найти на Bealdung, где формируется простой пример. На мой взгляд, это хороший источник для начала работы. Если вы понимаете это, попробуйте Google. Есть много хороших источников, чтобы многое перечислить здесь. Также взгляните на Google AutoService, который использует процессор аннотаций, чтобы избавить вас от необходимости создавать и обслуживать служебные файлы. Если вы хотите создавать классы, я рекомендую взглянуть на JavaPoet.

К сожалению, этот API не позволяет нам манипулировать исходным кодом. Но если вы действительно хотите, вы должны взглянуть на Project Lombok. Они делают это, но это не поддерживается.


Почему это важно (читаем дальше для заинтересованных лиц)

TL; DR: Меня очень удивляет, почему мы используем статическое метапрограммирование не столько как динамическое, потому что оно имеет много преимуществ.

Большинство разработчиков видят "Динамический и статический" и сразу же приходят к выводу, что динамика лучше. Ничего страшного в этом нет, у static есть много негативных коннотаций для разработчиков. Но в этом случае (и особенно для Java) это как раз наоборот.

Динамическое метапрограммирование требует отражений, которые имеют некоторые основные недостатки. Их очень много. Вкратце: производительность, безопасность и дизайн.

Статическое метапрограммирование (то есть обработка аннотаций) позволяет нам пересекать компилятор, который уже выполняет большинство вещей, которые мы пытаемся выполнить с помощью отражений. В этом процессе мы также можем создавать классы, которые снова передаются обработчикам аннотаций. Затем вы можете (например) генерировать классы, которые делают то, что обычно должно было быть сделано, используя отражения. Более того, мы можем внедрить систему "fast fast", потому что мы можем информировать компилятор об ошибках, предупреждениях и тому подобном.

Подводим итоги и сравниваем как можно больше: представим себе весну. Spring пытается найти все аннотированные классы Component во время выполнения (что мы могли бы упростить, используя служебные файлы во время компиляции), затем генерирует некоторые прокси-классы (что мы уже могли бы сделать во время компиляции) и разрешает зависимости bean-компонентов (что, опять же, мы уже мог бы сделать во время компиляции). Джейк Уортонс рассказывает о Dagger2, в котором он объясняет, почему они переключились на статическое метапрограммирование. Я до сих пор не понимаю, почему крупные игроки, такие как Spring, не используют его.

Этот пост является кратким, чтобы полностью объяснить эти различия и почему статика будет более мощной. Если хотите, я сейчас работаю над презентацией для этого. Если вы заинтересованы и говорите по-немецки (извините за это), вы можете взглянуть на мой веб-сайт. Там вы найдете презентацию, которая пытается объяснить различия в 45 минут. Только слайды, хотя.

Ответ 10

Проект Manifold предлагает безопасное для типов статическое метапрограммирование для Java. Вы можете использовать его для динамического построения типов во время компиляции, поскольку Javac разрешает имена типов. Демонстрация JSON Schema демонстрирует статическое метапрограммирование в терминах динамической проекции типа во время компиляции (без этапов сборки кода).

Кроме того, вы можете использовать коллектор для добавления новых функций. Проверьте структурную типизацию, расширения метода и безопасное отражение. ,

Ответ 11

Я не уверен, что понимаю преимущество статического метапрограммирования.

В Java вы можете подумать, чтобы найти информацию о своих классах и сделать все, что сделает метапрограммирование, вы просто можете сделать их внутри своего кода, не добавляя новый синтаксис и различные способы мышления. Аннотации также могут выполнять определенные задачи метапрограммирования более структурированным способом.

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

Если бы кто-нибудь мог ответить ссылкой на пример, где мета-программирование предлагает более понятное, читаемое или иное лучшее решение, чем отражение, я бы оценил усилия.