LINUX.ORG.RU

Java - получить класс типа-примитива по имени

 


0

2

Организую interpop с java. Все работает, создаю классы методом Class.forName(...), инстансы, нахожу методы и вызываю их с параметрами. Для нахождения методов использую getDeclaredMethod(methodName, paramTypes), в массив параметров типов метода помещаю опять же классы,найденные по имени. Но некоторые методы в качестве параметров принимают типы-примитивы, и передача им Class.forName(«java.lang.Double») напрямую не работает. Работает double.class или Double.TYPE. Но последние варианты неудобно получать из строки - надо заводить отдельную таблицу соответствия строка - примитивный тип. Может есть какой-нибудь удобный метод получения класса типа-примитива из какго-либо строкового представления?


Примитивных типов вроде 8 штук всего, завести быстрее, чем на ЛОРе тему создавать.

А вообще я не понимаю — откуда ты берёшь эти строковые названия. Исходники парсишь? Может тебе подойдёт метод getDeclaredMethods?

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Хорошо, заведу табличку. Просто думал может есть какой метод. Строковые названия - из названий классов и методов. getDeclaredMethods хорошая идея, думаю ее. Но он возвращает массив, хотя я могу (наверное) сначала руками создать методы обработки массива и потом написать макрос, который берет все методы объекта разом. Мне будет нужен сам метод, его строковое имя (getName наверное) можно будет заинтерпопить и самое главное - список типов параметров. А методы бывают перегруженные.... И может от вернет их все.... Короче, есть еще вопросы. А пока, например, вызов статических методов класса выглядит примерно так:

(defn sin (x) (invoke-st (method (class "java.lang.Math") "sin" "double") x))
С динамическими примерно так же, только создается экземпляр класса и передается в качестве параметра.

Ivana
() автор топика
Ответ на: комментарий от stevejobs

stevejobs - все просто - чтобы из интерпретируемого языка, написанного на java, иметь доступ к объектам и методам самой java. По-моему это называется interpop. Очень удобно - все синусы и хэшмапы и прочее получаем задаром, даже свинговые окошки открываются вызовом из интерпретатора.

Ivana
() автор топика
Ответ на: комментарий от Ivana

Просто думал может есть какой метод.

Есть вот такой: java.lang.Class#getPrimitiveClass. Но он не публичный, лучше табличкой.

Моя имха — если делать по уму — тебе надо через getDeclaredMethods найти метод с подходящим именем. Если таких методов несколько — найти метод, у которого число параметров совпадает с переданным (не забыть про varargs). До этого момента всё делается при компиляции (если у тебя есть такая фаза). Если же у тебя до сих пор осталось несколько методов, то тут уже надо идти по переданным параметрам, сравнивать их типы с типами методов и выбирать наиболее подходящий. В этом случае можно будет писать что-нибудь вроде (Math.sin x) и для такого тебе даже обёртки не надо будет делать, достаточно все классы из java.lang импортировать по умолчанию.

Ну или как ты делаешь, делать, но тут придётся всю стандартную библиотеку оборачивать в обёртки. Обычно стараются придумать способы максимально удобно её использовать без обёрток.

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 2)
Ответ на: комментарий от Ivana

а сам интерпретируемый язык на чем написан? В смысле я понял что на java, там есть какой-то движок типа AntLR или все вручную?

это промышленный софт, или что-то для себя, или вообще курсач? Чтобы понять масштаб проблемы

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)
Ответ на: комментарий от Legioner

Legioner, традиционное спасибо за развернутый ответ и идеи. Насчет метода взятия класса примитивов - что-то такое хитрое я и предполагал, но если говорите что лучше табличкой - уже сделал, точнее кейс по строке. Насчет поиска нужного метода... Фазы компиляции у меня нет, но я могу при загрузке моей библиотеки (в режиме интерпретации) связать все найденные методы с именами в глобальном пространстве имен, чтобы не искать их каждый раз когда они понадобятся. Ключевое слово invoke можно убрать как вы предлагаете, спасибо. Тогда если вычисленная головная форма списка имеет тип Метод, то его надо исполнять с переданными остальными аргументами. Только остается один вопрос - отличить статические методы от динамических и передавать последним объект в качестве параметра - выделить его из параметров собственно метода. А Math.sin в вашем примере будет переменной, которой присвоено значение найденного при загрузке библиотеки метода.

Ivana
() автор топика
Ответ на: комментарий от stevejobs

Все вручную, без единого гвоздя (только Swing для гуя и HashMap из стандартных классов). Можете посмотреть кот, я давал ссылку на гитхаб в прошлой теме. Можете также поругать убогость парсера, синтакс-хайлайтера и вообще всего :)

Ivana
() автор топика
Ответ на: комментарий от stevejobs

Это не промышленный софт и не курсач (я уже давно отучился, слава Б-гу), это пет-прожект для себя, побаловаться.

Ivana
() автор топика
Ответ на: комментарий от Ivana

Только остается один вопрос - отличить статические методы от динамических и передавать последним объект в качестве параметра - выделить его из параметров собственно метода.

Modifier.isStatic(method.getModifiers())

Legioner ★★★★★
()
Последнее исправление: Legioner (всего исправлений: 1)
Ответ на: комментарий от stevejobs

Не понимаю как связано «вручную» и сабжевая тема топика, но ладно ) Просто любопытно, чем в принципе могли бы помочь, если бы было не вручную, а на чужих тяжеловесных либах.

Ivana
() автор топика
Ответ на: комментарий от Legioner

Legioner, пора брать Вас в соавторы :) Точно, метод в голове списка, если он динамический - второй параметр рассматриваем как объект а остальные - как параметры метода, если статический - то все как параметры метода. И не нужны никакие ключевые формы для вызова - только для создания класса, экземпляра, и поиска метода.

Ivana
() автор топика
Ответ на: комментарий от Legioner

Все работает, никаких функций-оберток, только определение методов и связь их с именами!...

(def Math.sin (method (class "java.lang.Math") "sin" "double"))
(def Math.cos (method (class "java.lang.Math") "cos" "double"))

(def HashMap.put (method (class "java.util.HashMap") "put" "java.lang.Object" "java.lang.Object"))

(def HashMap.get (method (class "java.util.HashMap") "get" "java.lang.Object"))

(def HashMap.remove (method (class "java.util.HashMap") "remove" "java.lang.Object"))

(def showMessageDialog (method (class "javax.swing.JOptionPane")
            "showMessageDialog" "java.awt.Component" "java.lang.Object"))
Вызов прозрачный - (метод [объект] параметры), типа (Math.sin x). Осталось действительно, как Вы говорите, только загрузить при старте все нужные методы. Хотя в такой реализации не решена проблема одноименных перегруженных методов. Надо подумать на свежую голову, я понял как Вы предлагали ее решить, но может какой компромисс навелосипедю.

Ivana
() автор топика
Ответ на: комментарий от Ivana

ну есть всякие штуки типа https://www.jetbrains.com/mps/, там были бы вообще другие вопросы

вообще непонятно, зачем нужен рефлекшен для вызова методов из джавовских классов. После компиляции они все равно иммутабельны (можно сделать не иммутабельными, но это адский оверхед). Для иммутабельных классов путь до названия метода всегда один и тот же. Я так понял ты парсишь свой язык в аст, и потом его исполняешь в рантайме, за этим тебе и нужен рефлекше. Можно сделать наоброт - транслировать всю твою программу 1-в-1 прямо в джава-код и собрать этот джава-код джавовским компилятором. Если сама java слишком restrictive, можно компилировать прямо в сам JVM с помощью https://github.com/raphw/byte-buddy или что там сейчас модно

Тут сразу же возникает вопрос в методах задания формальной грамматики и формальных правил трансляции аст->джавакод, чтобы сборкой можно было удобно управлять. И твой вопрос трансформируется из «может есть какой-нибудь удобный метод получения класса» в вопрос как правильно на тулзе описания грамматики описать нужный тебе синтаксис, и как в целом достичь нужной тебе семантики

stevejobs ★★★★☆
()
Последнее исправление: stevejobs (всего исправлений: 1)

Я вас верно понял? =)

forName(String name)
Replacement for Class.forName() that also returns Class instances for primitives (like «int») and array class names (like «String[]»).

ЕМНИП, код под апач2 лицензией, так что, в-принципе, вам можно и не тащить весь фреймворк, если нужен только этот функционал.

К сожалению, в Java такого функционала по умолчанию нет.

znenyegvkby
()
Ответ на: комментарий от stevejobs

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

znenyegvkby, я не большой знаток лицензий, я жертва ИДЕ и интернета - нашел примеры, скопипастил, IDEA мне подгрузила нужные классы и я надеюсь что ничего лишнего я не тащу в проект и меня потом не засудят за нарушение авторских прав :)

ЗЫ сейчас решаю вопрос синтаксиса. Тащить в пространство имен все методы всех классов имеет свои минусы, к тому же сложнее с реализацией перегруженных методов с одним именем - надо связывать с именем массив методов. Пока вижу такой вариант - каждый раз искать нужный метод по имени и количеству/типам переданных параметров, как предложил Legioner. И немного переделать мой синтаксис, чтобы работало примерно так:

(def Math (class "java.lang.Math")) //связывает класс с именем
(Math "sin" 1.1) // вызывает найденный статический метод с параметром
(def m ((class "java.util.HashMap") "new")) // создает экземпляр
(m "put" 1 "123") // вызывает найденные динамические методы с параметрами
(m "get" 1)
(person "name") // получает значение поля класса или экземпляра
(person "name" "Andrey") // устанавливает значение поля класса или экземпляра
(5 "doubleValue") // вызывает метод объекта
Первым параметром идет класс или экземпляр. Вторым - всегда строка, ищу сначала поле с таким именем, если не нахожу - ищу метод. Если это поле и больше параметров нет - возвращаю значение этого поля, если параметр есть - воспринимаю это как установку значение поля, если это метод - вызываю его с переданными параметрами (количество и типы детализируют конкретный метод). Что-то упустил? С разными конструкторами экземпляров надо что-то придумать, можно передавать после «new» параметры и искать по ним нужный конструктор. Если вообще возможно передать в newInstance() параметры.

Ivana
() автор топика
Ответ на: комментарий от Ivana

я не большой знаток лицензий, я жертва ИДЕ и интернета - нашел примеры, скопипастил, IDEA мне подгрузила нужные классы и я надеюсь что ничего лишнего я не тащу в проект и меня потом не засудят за нарушение авторских прав :)

Не засудят, это же apache 2 license. Вы главное не имейте привычки затирать чужие копирайты, ну вообщем вы поняли.

С разными конструкторами экземпляров надо что-то придумать, можно передавать после «new» параметры и искать по ним нужный конструктор. Если вообще возможно передать в newInstance() параметры.

Но ведь в этом и суть Reflection. То есть мне не нужно знать имена исследуемых объектов (интерфейсов/классов/методов/etc). Иначе в нем не было бы смысла. Я не совсем понимаю что конкретно вы хотите искать.

И еще, может быть не стоит пытаться уместить все в одном методе? В любом случае я не вижу проблемы, вы просто вызываете new Some (someArg1, someArg2, etc) и получаете либо экземпляр - либо NoSuchMethodException. Но все же мне не до конца ясно что вы имели ввиду под

передавать после «new» параметры и искать по ним нужный конструктор.

поясните, пожалуйста.

znenyegvkby
()

com.google.common.primitives.Primitives

cdshines ★★★★★
()
Ответ на: комментарий от znenyegvkby

znenyegvkby, допускаю, что вам не нужно знать имена исследуемых объектов (интерфейсов/классов/методов/etc), но я без имени «sin» синус не найду. А с именем - найду двадцать синусов - от целого аргумента в градусах, от вещественного в радианах, от двух аргументов, представляющих одно комплексное число и т.п. И мне надо решить, какой именно применить. Выше же обсуждалось это. С конструкторами экземпляров та же ситуация - http://stackoverflow.com/questions/234600/can-i-use-class-newinstance-with-co...

Ivana
() автор топика
Ответ на: комментарий от Ivana

передавать после «new» параметры

в коде моих скриптов разумеется, а не в java-коде.

Ivana
() автор топика
Ответ на: комментарий от Ivana

Я скорее всего неточно выразился. Под

То есть мне не нужно знать имена исследуемых объектов

Я подразумеваю то, что мне не нужно знать существуют ли они. Когда я говорю «я не знаю», я подразумеваю что именно Я это не знаю, а не машина. Программа, естественно, знает :)

По поводу различия сигнатур методов/конструкторов, тоже ясно. Вы юзаете

c.getDeclaredConstructor();
если уверены что сигнатура не содержит входных параметров, и
c.getDeclaredConstructor(Integet.class);
если уверены что сигнатура содержит один параметр int.

Понятное дело что определение «если уверены» определяется вашей программой. Я же просто не понял вашего высказывания, и не мог понять что вы хотите там искать

С разными конструкторами экземпляров надо что-то придумать, можно передавать после «new» параметры и искать по ним нужный конструктор.

А сейчас увидел дополнение

в коде моих скриптов разумеется, а не в java-коде.

и все стало на свои места.

znenyegvkby
()
Ответ на: комментарий от znenyegvkby

Мысли с полей: сделал поиск метода по имени и количеству/типам параметров, через перебор getDeclaredMethods(). Но каждый раз так искать долго и неэффективно, поэтому хорошо бы иметь более прямой и быстрый доступ к методам. Вариантов несколько:

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

- предварительное заполнение глобального пространства имен методами. Всеми, которые могут в принципе пригодиться. А это дофига. Поэтому нет.

- мемоизация. При первом поиске метода он добавляется в таблицу по хэш-ключу Класс/имя метода/массив типов параметров. И потом сначала ищется в этой таблице, а если нет - честно перебирает getDeclaredMethods(). Не идеал конечно, но имхо в данной ситуации нормальный компромисс. Буду пробовать.

Ivana
() автор топика
Ответ на: комментарий от Ivana

Хм. Третий вариант самый разумный, ИМХО. Java сама так собирает конечную сигнатуру метода (из имени + сигнатуры параметров)

Two methods have the same signature if they have the same name and argument types.

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

В любом случае доступ через хэш будет куда быстрее чем

сделал поиск метода по имени и количеству/типам параметров, через перебор getDeclaredMethods().

Удачи вам в начинаниях!

znenyegvkby
()
Ответ на: комментарий от znenyegvkby

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

znenyegvkby
()

Итого на текущий момент через reflection доступны стандартные пакеты lang и util с математическими функциями и коллекциями и остальное, что загружается по умолчанию, но пока мною не пробованное и следовательно неизвестное. Частично доступны swing-овые вещи - могу создавать модальные выпадающие окошки, обычные окна с добавленными элементами, даже удалось победить графику - могу рисовать графические примитивы на фрейме и они не пропадают при ресайзе (напомню, все через reflection, никаких собственных классов-наследований и переписываний методов paint() и т.п.). Только на обработчике событий кнопок я конечно пожух. Создавать в рантайме новые AbstractAction и тем более писать java-код их методов я пока не осилил.

Ivana
() автор топика

велосипед даже велосипедом назвать сложно

знаете что он делает,а я вам объеяню

вот допустим,для примера возьмем джаваскрипт
в джаваскрипте есть синтаксис,если функции,если графический вывод...
так вот одному гению пришло в голову
а что если-я напишу «джаваскрипт код»(на синтаксисе джааскрипта)
который примет моя написанная функция и будет транслировать этот код в реалтайме
тоесть function(my.js){и функция построчно читает my.js и выполняет весь текст как джаваскрипт код,внутри этой функции}.......

это ужасает до ужаса

ЗАЧЕМ ТЫ ДЕЛАЕШЬ ЭТОТ МАРАЗМ В КУБЕ

У ТЕБЯ ЕСТЬ РЕАЛТАЙМ JAVAC КОТОРАЯ РЕАЛТАЙМ МОЖЕТ КОМПИЛЯТЬ .JAVA ИСХОДНИК И РЕАЛТАЙМ(ДА БЛ-ТЬ) ПОДГРУЖАТЬ ЕГО К ЛЮБОМУ АКТИВНОМУ ПРИЛОЖЕНИЮ ИЛИ ТЫ САМ ИЗ ПРИЛОЖЕНИЯ МОЖЕШЬ ПОДКЛЮЧАТЬ НОВЫЙ .CLASS ПО ХОДУ
ЗАЧЕМ ТЕБЕ ТРАНСЛИРОВАТЬ ДЖАВА КОД В ДЖАВА ПОСТРОЧКАМ ТЕКСТОВЫМ ЕЩЕ И ГОРДИТЬСЯ ЕЩЕ И ПЕРЕПИСЫВАТЬ ЧТОТО

ЧТО ТЫ ДЕЛАЕШЬ ОСТАНОВИСЬ ДЕМОН

tem3
()
Ответ на: комментарий от tem3

Спасибо за такое эмоциональное неравнодушие :) Я же java увидел впервые месяц назад, захотел interpop, нашел в инете примеры eval, не впечатлился, reflection вроде подошло, навелосипедил. От вас узнал что оказывается можно вообще на лету из работающего приложения текст кода компилить и подгружать - ваще бомба :) Значит плюс к reflection-у попробую еще и этот механизм, если получится конечно.

Ivana
() автор топика
Ответ на: комментарий от Ivana

Только на обработчике событий кнопок я конечно пожух. Создавать в рантайме новые AbstractAction и тем более писать java-код их методов я пока не осилил.

Попробуй использовать java.lang.reflect.Proxy

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Спасибо, посмотрю и попробую применить. А пока вот такое баловство вполне получается http://www.cyberforum.ru/post8700794.html (прошу прощения, если кот задевает чьи-то чувства...)

Ivana
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.