JNI: создать HashMap - PullRequest
       28

JNI: создать HashMap

11 голосов
/ 30 января 2011

Как мне создать объект HashMap в JNI?

Ответы [ 5 ]

18 голосов
/ 19 мая 2011

Вот код, который вам нужно будет изменить для работы

jclass mapClass = (*env)->FindClass(env, "java/util/HashMap");
if(mapClass == NULL)
{
    return NULL;
}


jsize map_len = 1;

jmethodID init = (*env)->GetMethodID(env, mapClass, "<init>", "(I)V");
jobject hashMap = (*env)->NewObject(env, mapClass, init, map_len);

jmethodID put = (*env)->GetMethodID(env, mapClass, "put",
            "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

while( ... )
{
    jint key = ...;
    size_t sz = t->count;
    jbyteArray dd = (*env)->NewByteArray(env, sz);
    for(i = 0; i < sz; i++)
    {
        (*env)->SetByteArrayRegion(env, dd, i, 1, *data++);
    }

    (*env)->CallObjectMethod(env, hashMap, put, key, dd);

    (*env)->DeleteLocalRef(env, key);
    (*env)->DeleteLocalRef(env, dd);
}

(*env)->DeleteLocalRef(env, hashMap);
(*env)->DeleteLocalRef(env, mapClass);
3 голосов
/ 18 декабря 2012

Для меня я обнаружил, что подпись метода "put" должна отличаться от подписи в примере вышет.е.

jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
2 голосов
/ 05 декабря 2018

Ниже мой вклад в этот вопрос, я использовал идеи из других ответов и других местах.Ниже приведены две функции, которые преобразуют std::map<std::string, std::string> в HashMap и обратно:

jobject StlStringStringMapToJavaHashMap(JNIEnv *env, 
                                        const std::map<std::string, std::string>& map);
void JavaHashMapToStlStringStringMap(JNIEnv *env, jobject hashMap, 
                                     std::map<std::string, std::string>& mapOut);

Функция тестирования:

void TestConversions(JNIEnv *env);

дает примеры, как ее использовать - кстати.Я запустил этот тест на устройстве Android, и он работает.

jobject StlStringStringMapToJavaHashMap(JNIEnv *env, const std::map<std::string, std::string>& map) {
  jclass mapClass = env->FindClass("java/util/HashMap");
  if(mapClass == NULL)
    return NULL;

  jmethodID init = env->GetMethodID(mapClass, "<init>", "()V");
  jobject hashMap = env->NewObject(mapClass, init);
  jmethodID put = env->GetMethodID(mapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");

  std::map<std::string, std::string>::const_iterator citr = map.begin();
  for( ; citr != map.end(); ++citr) {
    jstring keyJava = env->NewStringUTF(citr->first.c_str());
    jstring valueJava = env->NewStringUTF(citr->second.c_str());

    env->CallObjectMethod(hashMap, put, keyJava, valueJava);

    env->DeleteLocalRef(keyJava);
    env->DeleteLocalRef(valueJava);
  }

  jobject hashMapGobal = static_cast<jobject>(env->NewGlobalRef(hashMap));
  env->DeleteLocalRef(hashMap);
  env->DeleteLocalRef(mapClass);

  return hashMapGobal;
}

// Based on android platform code from: /media/jni/android_media_MediaMetadataRetriever.cpp
void JavaHashMapToStlStringStringMap(JNIEnv *env, jobject hashMap, std::map<std::string, std::string>& mapOut) {
  // Get the Map's entry Set.
  jclass mapClass = env->FindClass("java/util/Map");
  if (mapClass == NULL) {
    return;
  }
  jmethodID entrySet =
    env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;");
  if (entrySet == NULL) {
    return;
  }
  jobject set = env->CallObjectMethod(hashMap, entrySet);
  if (set == NULL) {
    return;
  }
  // Obtain an iterator over the Set
  jclass setClass = env->FindClass("java/util/Set");
  if (setClass == NULL) {
    return;
  }
  jmethodID iterator =
    env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;");
  if (iterator == NULL) {
    return;
  }
  jobject iter = env->CallObjectMethod(set, iterator);
  if (iter == NULL) {
    return;
  }
  // Get the Iterator method IDs
  jclass iteratorClass = env->FindClass("java/util/Iterator");
  if (iteratorClass == NULL) {
    return;
  }
  jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z");
  if (hasNext == NULL) {
    return;
  }
  jmethodID next =
    env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;");
  if (next == NULL) {
    return;
  }
  // Get the Entry class method IDs
  jclass entryClass = env->FindClass("java/util/Map$Entry");
  if (entryClass == NULL) {
    return;
  }
  jmethodID getKey =
    env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;");
  if (getKey == NULL) {
    return;
  }
  jmethodID getValue =
    env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;");
  if (getValue == NULL) {
    return;
  }
  // Iterate over the entry Set
  while (env->CallBooleanMethod(iter, hasNext)) {
    jobject entry = env->CallObjectMethod(iter, next);
    jstring key = (jstring) env->CallObjectMethod(entry, getKey);
    jstring value = (jstring) env->CallObjectMethod(entry, getValue);
    const char* keyStr = env->GetStringUTFChars(key, NULL);
    if (!keyStr) {  // Out of memory
      return;
    }
    const char* valueStr = env->GetStringUTFChars(value, NULL);
    if (!valueStr) {  // Out of memory
      env->ReleaseStringUTFChars(key, keyStr);
      return;
    }

    mapOut.insert(std::make_pair(std::string(keyStr), std::string(valueStr)));

    env->DeleteLocalRef(entry);
    env->ReleaseStringUTFChars(key, keyStr);
    env->DeleteLocalRef(key);
    env->ReleaseStringUTFChars(value, valueStr);
    env->DeleteLocalRef(value);
  }
}

void TestConversions(JNIEnv *env) {

  // Empty test
  {
    std::map<std::string, std::string> map, mapTest;
    jobject hashMap = StlStringStringMapToJavaHashMap(env, map);
    JavaHashMapToStlStringStringMap(env, hashMap, mapTest);
    assert(map == mapTest);
  }

  // One element test
  {
    std::map<std::string, std::string> map, mapTest;
    map["one"] = "uno";
    jobject hashMap = StlStringStringMapToJavaHashMap(env, map);
    JavaHashMapToStlStringStringMap(env, hashMap, mapTest);
    assert(map == mapTest);
  }

  // Two element test
  {
    std::map<std::string, std::string> map, mapTest;
    map["one"] = "uno";
    map["two"] = "duo";
    jobject hashMap = StlStringStringMapToJavaHashMap(env, map);
    JavaHashMapToStlStringStringMap(env, hashMap, mapTest);
    assert(map == mapTest);
  }

  // Huge number of elements test
  {
    std::map<std::string, std::string> map, mapTest;
    for (int n = 0; n < 10000; ++n) {
      map[std::to_string(n)] = std::to_string(n);
    }
    jobject hashMap = StlStringStringMapToJavaHashMap(env, map);
    JavaHashMapToStlStringStringMap(env, hashMap, mapTest);
    assert(map == mapTest);
  }
}
2 голосов
/ 28 ноября 2015

Можно также рассмотреть альтернативы непосредственному использованию JNI - например, инструменты, которые могут генерировать код JNI для вас.Например, JANET (заявление об отказе: я написал) позволяет встраивать Java-код в ваши собственные методы, поэтому создание и использование хэш-карты будет таким простым:

... (C++ code)
`Map map = new HashMap();` // embedded Java
... (C++ code)
... const char* foo = "foo";
`map.put(#$(foo), 50);` // ["foo" -> 50]

операторы с обратной галочкой преобразуются JANET в код JNI, поэтому вам не нужно беспокоиться о сигнатурах, обработке ссылок, обработке исключений и т. д., но вы все равно получаете производительность JNI.

2 голосов
/ 30 января 2011

См. здесь :

Пример кода для вызова конструктора String:

jstring
 MyNewString(JNIEnv *env, jchar *chars, jint len)
 {
     jclass stringClass;
     jmethodID cid;
     jcharArray elemArr;
     jstring result;

     stringClass = (*env)->FindClass(env, "java/lang/String");
     if (stringClass == NULL) {
         return NULL; /* exception thrown */
     }
 /* Get the method ID for the String(char[]) constructor */
     cid = (*env)->GetMethodID(env, stringClass,
                               "<init>", "([C)V");
     if (cid == NULL) {
         return NULL; /* exception thrown */
     }

     /* Create a char[] that holds the string characters */
     elemArr = (*env)->NewCharArray(env, len);
     if (elemArr == NULL) {
         return NULL; /* exception thrown */
     }
     (*env)->SetCharArrayRegion(env, elemArr, 0, len, chars);

     /* Construct a java.lang.String object */
     result = (*env)->NewObject(env, stringClass, cid, elemArr);

     /* Free local references */
     (*env)->DeleteLocalRef(env, elemArr);
     (*env)->DeleteLocalRef(env, stringClass);
     return result;
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...