JNI Basic for NDK -4
C++ 2012. 12. 27. 22:38 |JNI Basic for NDK - 4
필드와 메써드
글을 쓰다보니 처음 의도와는 달리 JNI Programmer's guide and Specification을 거의 베끼는 형식이 되어가고 있습니다. 단지 예제를 그냥 안드로이드 환경에 맞도록 조금 수정하는 정도의 차이 밖에 없지만 나름 의미가 있다고 생각하고 계속 진행하도록 하겠습니다.
원본이 보고 싶으신 분은 “Java Native Interface: Programmer's Guide and Specification”
http://java.sun.com/docs/books/jni/ 를 참고하세요.
지금까지 JNI가 네이티브 메써드에서 어떻게 기본형 데이터와 참조형 데이터를 다루는지를 봤습니다. 이제는 오브젝트의 필드와 메써드를 접근하는 방법을 알아보도록 하겠습니다.
1. 필드에 접근하기
Java에서는 두가지 종류의 필드가 있습니다. 클래스의 인스턴스는 클래스의 복사본 형태로 자신만의 '인스턴스 필드'를 가지고 있습니다. 하지만 '스태틱 필드'는 모든 인스턴스가 동일한 필드를 공유를 합니다.
JNI에서는 이 두가지 필드를 읽거나 수정을 할 수 있는 방법을 모두 제공하고 있습니다. 우선 인스턴스 필드를 접근하는 예제를 보도록 하겠습니다. 이클립스에서 InstanceFieldAccess라고 하는 프로젝트를 생성하고 InstanceFieldAccessActivity를 아래와 같이 수정합니다.
public class InstanceFieldAccessActivity extends Activity { private native void accessField(); TextView tv = new TextView(this); |
InstanceFieldAccessActivity 클래스에는 s라고 하는 String형의 인스턴스 필드가 있습니다. 이 필드는 onCreate에서 'abc'로 값이 세팅이 됩니다. 다음에 accessField라고하는 네이티브 메써드를 호출합니다. 이 메써드는 인스턴스 필드인 s에 저장된 문자열을 다른 것으로 변경을 할 것입니다. 그 변경된 내용은 TextView에 표시가 됩니다.
accessField의 네이티브 메써드 구현은 아래와 같습니다.
#include <stdio.h> JNIEXPORT jstring JNICALL Java_ndk_instancefieldaccess_InstanceFieldAccessActivity_accessField jstr = (*env)->NewStringUTF(env, "123"); |
ndk-build로 컴파일하고 이클립스에서 실행을 하면 아래와 같은 내용이 디스플레이 됩니다.
1.1 인스턴스 필드에 접근하는 방법
인스턴스 필드에 접근하기 위해서는 세 단계의 과정을 거쳐야합니다.
jclass cls = (*env)->GetObjectClass(env, obj);
GetObjectClass를 호출하여 클래스 레퍼런스를 얻어옵니다.
fid = (*env)->GetFieldID(env, cls, "s", "Ljava/lang/String;");
필드 아이디를 얻기 위해서 GetFieldID를 호출합니다. 이때 앞에서 얻은 클래스 레퍼런스인 cls와 필드 이름과 필드 디스크립터가 인자로 사용이 됩니다.
jstrOrg = (*env)->GetObjectField(env, obj, fid);
필드 아이디를 구한 후에는 GetObjectField를 호출하여 원하던 인스턴스 필드를 얻어옵니다.
스트링은 기본형이 아닌 오브젝트라서 Get/SetObjectField라는 함수를 사용했습니다. 기본형 데이터에 대해서는 GetIntField나 SetFloatField 같은 함수를 JNI에서 별도로 제공합니다.
1.2 필드 디스크립터
앞에서 본 "Ljava/lang/String;"를 JNI 필드 디스크립터라고 합니다. 이는 Java의 필드 타입을 표현한 C 스트링입니다.
기본형에 대해서는 int는 "I", float는 "F", double은 "D", boolean은 "Z" 같은 식으로 표현이 됩니다.
java.lang.String과 같은 레퍼런스 타입의 경우는 L로 시작을 해서 JNI 클래스 디스크립터가 나오고 마지막으로 세미콜론(;)으로 끝납니다. JNI 클래스 디스크립터는 클래스의 전체 이름에서 '.'를 '/'로 치환한 것입니다. java.lang.String은 아래와 같이 됩니다.
"Ljava/lang/String;"
배열에 대한 디스크립터는 "["와 배열의 요소의 데이터 타입으로 구성이 됩니다. int[]의 경우는 "[I"가 됩니다.
필드 디스크립터를 알아내기 위해서 javap라고 하는 tool을 사용할 수 있습니다. JNI 프로그래밍 중에서 불편한 것 중의 하나가 필드 디스크립터를 사용하는 것입니다. 그래도 javap를 사용하면 일을 좀 더 편하게 실수 없이 할 수 있습니다. 사용법은 현재 폴더가 jni 폴더라고 가정했을 때 아래와 같습니다. javap -classpath ../bin -s -private ndk.instancefieldaccess.InstanceFieldAccessActivity |
'C++' 카테고리의 다른 글
문자열 비교는 == 비교연산자 와 strcmp 어떤걸 써야 하는가.. (0) | 2013.10.10 |
---|---|
자바 객체의 사용 - NDK (0) | 2012.12.27 |
JNI Basic for NDK -3 (0) | 2012.12.27 |
JNI Basic for NDK -1 (0) | 2012.12.27 |
NDK C++ 자료 (0) | 2012.12.27 |