The Java language defines different data types, such as the basic types int, double, etc., as well as the parent class Object of all classes, etc. These are Java-level types, and the processing process using local methods requires their corresponding types.
The native methods written in the Java layer are compiled into bytecode by the compiler. The bytecode will record different types of parameters into class files according to the specification, such as B represents byte, I represents int, J represents long, etc. Then a local method as follows is recorded as (Ljava/lang/Object;II)V.
public static native void test(Object o, int i, int i2);
The corresponding methods above are registered in the JVM. When executed to call the local method, the local data type will be converted according to the type map, such as int->jint and Object->jobject. In fact, int and jint are the same in C++, just use typedef to define another name. jobject is a pointer. The execution engine generates an Object object when executing Java layer logic. It has a special data structure in the JVM layer. The jobject here is a pointer to this structure. When it needs to be used, it can be cast into the data structure of the JVM layer, and then it can be operated on. In addition, Oop is used in the JVM to represent object pointers.
| Java Type | Native Type | value |
|---|---|---|
| boolean | jboolean | true or false |
| byte | jbyte | -128~127 |
| Short | jshort | -pow(2,15)~pow(2,15)-1 |
| int | jint | -pow(2,31)~pow(2,31)-1 |
| long | jlong | -pow(2,63)~pow(2,63)-1 |
| float | jfloat | IEEE754 standard single-precision floating point number |
| double | jdouble | IEEE754 standard double precision floating point number |
| char | jchar | 16-bit unsigned, Unicode characters |
In addition to the basic type mapping, other object types in the Java layer are reference types, so the local method corresponds to the jobject type. In addition, it will also derive some commonly used subclasses, such as jstring, jclass, etc., as follows,
class _jobject {};class _jclass : public _jobject {};class _jthrowable : public _jobject {};class _jstring : public _jobject {};class _jrray : public _jobject {};class _jbooleanArray : public _jarray {};class _jbyteArray : public _jarray {};class _jcharArray : public _jarray {};class _jshortArray : public _jarray {};class _jintArray : public _jarray {};class _jlongArray : public _jarray {};class _jfloatArray : public _jarray {};class _jdoubleArray : public _jarray {};class _jobjectArray : public _jarray {};You can see that the _jobject class is defined, which is an empty class, while other classes include _jclass _jthrowable _jstring _jarray, are all inherited from the _jobject class. In addition, the array type also derives 9 subclasses, corresponding to the base type array and the reference type array respectively.
After defining the class, define the pointer alias. Here is the type of the local method. In addition, these are C++ definitions. If it is a C compiler, it will use struct to define _jobject, not class.
typedef _jobject *jobject;typedef _jclass *jclass;typedef _jthrowable *jthrowable;typedef _jstring *jstring;typedef _jarray *jrray;typedef _jbooleanArray *jbooleanArray;typedef _jbyteArray *jbyteArray;typedef _jcharArray *jcharArray;typedef _jshortArray *jshortArray;typedef _jintArray *jintArray;typedef _jlongArray *jlongArray;typedef _jfloatArray *jfloatArray;typedef _jdoubleArray *jdoubleArray;typedef _jobjectArray *jobjectArray;
The above reference type is defined as an empty class. Here we understand the empty class in C++. Usually, we need to define an empty class in the following two ways.
class Empty{}struct Empty{}After the above definition, the size of an empty class is 1, but what is the use of an empty class if there is nothing? In fact, it can be used to distinguish different objects. Different objects defined by empty classes have different addresses. Objects operated using new also have different pointers. In addition, empty classes can also distinguish different categories.
So how do we use these type mappings in connection? It is actually very simple. The answer is to convert pointers. As mentioned earlier, objects in the Java layer have a certain data structure in the JVM, that is, use oop to represent object pointers. Then the job can be converted as follows, where handle is the job type.
oop result = *reinterpret_cast<oop*>(handle);
It is very convenient to further process it after converting it to OOP. For example, if you want to obtain some class-related metadata, you can use klass to obtain it.
Above, the types defined by the Java layer have corresponding data types in the local method. Moreover, the Java layer source code is compiled into bytecode and saves the types corresponding to the local method parameters. When executing the JVM, the type corresponding to the local method can be converted according to different types. The types defined by the local method are all empty classes. The main function is to bind objects and distinguish object types. The object or class metadata can be accessed through pointer conversion when necessary.