JNI-сигнатуры методов в Java

Буквально на днях на ISN была затронута тема взаимодействия java и native. Я решил продолжить данный тренд и написать о том, что было для меня самым сложным на первом этапе при работе с jni. Это всего лишь формат сигнатур методов которые необходимо указывать, чтобы получить экземпляр jmethodID. К сожалению, не всегда возможно/удобно использовать javap, так что умение писать jni-сигнатуры достаточно полезно.
Как и положено, для начала посмотрим документацию на sun.com:



















































Type Signature Java Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
L fully-qualified-class ; fully-qualified-class
[ type type[]
( arg-types ) ret-type method type

For example, the Java method:
long f (int n, String s, int[] arr);

has the following type signature:
(ILjava/lang/String;[I)J




Хм.. не густо и не особо понятно. Попробую описать своими словами.

JNI-сигнатура состоит из списка типов формальных параметров и типа возвращаемого значения. Формат записи похож на Pascal-style определения методов: сначала параметры потом возвращаемое значение (к слову, не многие знают что многие концепции Java были скопированы с языка и операционной системы Oberon являющихся дальнейшим развитием идей Н.Вирта, создателя Pascal). В JNI-сигнатурах пробелы запрещены - каждый символ имеет значение и не может быть выброшен без потери смысла. Элементы списка параметров не разделяются никакими символами. О обозначении типов формальных параметров ниже. Условно можно выделить 4 правила:



    1. Примитивные типы: кодируются соответствующей буквой латинского алфавита (см.таблицу выше):

    1. Массивы: для обозначения того, чо будет передаваться не скалярный тип, а массив используется символ "[". Находящееся правее квадратной скобки обозначение типа - тип элемента массива. Размер массива не обозначается.

    1. Ссылочные типы (объекты): Обозначение класса начинается с заглавной латинской L после которой идет без пробелов полное имя класса, состоящее из: пакета (вложенные пакеты разделяются слешами) и имени класса (также разделенных слешем). Запись является регистро-зависимой. После имени класса должна обязательно идти запятая, являющаяся окончанием определения типа. Обращаю внимание, что опускать запятую нельзя (в том числе и в описании типа возвращаемого значения метода).

    1. Возвращаемый тип void (т.е. ничего) заменяются символом "V"



Теперь продемонстрирую это на практике:

1. int MyMethod1(float a, char b) -> (FC)I

2. int[] MyMethod2(long[] a) -> ([J)[I

3. void MyMethod3(package1.subpackage2.MyClass[] a, String b) -> (Lpackage1/subpackage2/MyClass;Ljava/lang/String;)V

4. package1.subpackage2.MyClass[] MyMethod4(String a, Class[] b, float c) -> (Ljava/lang/String;[java/lang/Class;F)[Lpackage1/subpackage2/MyClass;


Так что магические на первый взгляд последовательности символов оказываются достаточно просты (с отличии от сигнатур в языке C).

P.S. Набирал эту заметку на планшете в метро. Оказалось, планшеты вполне пригодны для создания контента. Хотя над удобством клавиатуры андроида еще можно поработать))

Etiquetas:
Para obtener más información sobre las optimizaciones del compilador, consulte el aviso sobre la optimización.