C + + JAVA 호출 방법 상세 설명

13731 단어 C#C++CJavaJNI
더 읽 기
본문 은 주로 참고 한다.http://tech.ccidnet.com/art/1081/20050413/237901_1. html 의 글.
 
C + + 호출 JAVA 는 주로 SUN 사의 JNI 기술 을 사 용 했 고 JNI 는 자바 네 이 티 브 인터페이스 의 줄 임 말이다.자바 1.1 부터 자바 네 이 티 브 인터페이스 (JNI) 표준 은 자바 플랫폼 의 일부분 이 되 어 자바 코드 와 다른 언어 로 작 성 된 코드 가 상호작용 을 할 수 있 도록 합 니 다.관련 자료http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/jniTOC.html
 
개발 환경 설치 및 배치
 
1.1  JDK 설치        썬 컴 퍼 니 홈 페이지 에서 최신 판 JDK 를 다운로드 할 수 있다.다운로드 후 설 치 를 시작 합 니 다. 기본 설정 을 선택 하면 됩 니 다. 이 문서 에 설 치 된 것 은 JDK 1.4 이 고 설치 디 렉 터 리 는 C: \ j2sdk 1.4.2 입 니 다.15。   1.2  VC 6.0 설정         Visual C + + 6 메뉴 Tools → Options 를 통 해 옵션 대화 상 자 를 엽 니 다.Directories 탭 에 JDK 관련 디 렉 터 리 를 Include 와 디 렉 터 리 에 추가 합 니 다.              
 
 개발 테스트 에 사용 되 는 JAVA 류
2.1  JAVA 류 개발
        하 드 디스크 의 임의의 곳 에 test 라 는 폴 더 를 새로 만 듭 니 다. 이 문서 의 예제 에 서 는 test 폴 더 를 CD 루트 디 렉 터 리 에 만 든 다음 Demo. java 라 는 JAVA 파일 을 새로 만 들 고 아래 테스트 용 코드 를 이 파일 에 붙 입 니 다.
 
 
package test;
/**
*        JNI           
*/
public class Demo 
{
	//                 
	public static int COUNT = 8;
	//       
	private String msg;
	private int[] counts;
	
	public Demo() 
	{
		this("      ");
	}
	/**
	 *          
	 */
	public Demo(String msg) 
	{
		this.msg = msg;
		this.counts = null;
	}
	public String getMessage()
	{
		return msg;
	}
	/**
	 *                
	 */
	public static String getHelloWorld()
	{
		return "Hello world!";
	}

	/**
	 *                     
	 */
	public String append(String str, int i)
	{
		return str + i;
	}
	/**
	 *          
	 */
	public int[] getCounts()
	{
	 return counts;
	}
	/**
	 *             
	*/
	public void setCounts(int[] counts)
	{
	 this.counts = counts;
	}
	/**
	 *        
	*/
	public void throwExcp()throws IllegalAccessException
	{
		throw new IllegalAccessException("exception occur.");
	}
}

 
2.2 JAVA 클래스 컴 파일
      CMD 콘 솔 프로그램 을 실행 하여 명령 행 모드 로 들 어가 명령 자바 c - classpath c: \ c: \ test \ \ Demo. 자바, - classpath 매개 변 수 는 classpath 의 경 로 를 지정 합 니 다. 여기 가 test 디 렉 터 리 가 있 는 경로 입 니 다.(메모: JDK 의 환경 변 수 를 설정 하지 않 았 다 면 다음 그림 과 같이 JDK 의 bin 디 렉 터 리 에 먼저 들 어가 야 합 니 다.)
 
2.3 보기 방법의 서명
      자바 에서 허용 하 는 방법의 다 태 를 알 고 있 습 니 다. 단지 방법 명 을 통 해 구체 적 인 방법 을 찾 을 수 없 기 때문에 하나의 문자열 로 유일한 방법 을 표시 해 야 합 니 다.그러나 어떻게 하나의 문자열 을 이용 하여 방법의 구체 적 인 정 의 를 표시 합 니까?JDK 에는 역 컴 파일 도구 자바 p 가 준비 되 어 있 습 니 다. 이 도 구 를 통 해 클래스 의 모든 속성, 방법의 서명 을 받 을 수 있 습 니 다.CMD 에서 javap - s - p - classpath c: \ test. demo 를 실행 하면 속성 과 방법의 서명 을 볼 수 있 습 니 다.아래 그림 의 빨간색 사각형 상자 에 있 는 문자열 은 String append (String str, int i) 의 서명 방법 입 니 다.
 
 
VC 에서 JAVA 클래스 호출
 
3.1 JAVA 의 편지 빠 른 호출
      VC 에 콘 솔 프로그램 을 새로 만 든 다음 CPP 파일 을 새로 만 들 고 다음 코드 를 파일 에 추가 합 니 다.이 파일 을 실행 하면 데모 클래스 에서 String append (String str, int i) 함수 가 되 돌아 오 는 문자열 을 얻 을 수 있 습 니 다.
#include "windows.h"
#include "jni.h"
#include 
#include 
using namespace std;

jstring NewJString(JNIEnv *env, LPCTSTR str);
string  JStringToCString (JNIEnv *env, jstring str);

int main()
{
    //        ,      JVM  JNI_CreateJavaVM  
    typedef jint (WINAPI *PFunCreateJavaVM)(JavaVM **, void **, void *);
    
    int res;
    JavaVMInitArgs vm_args;
    JavaVMOption options[3];
    JavaVM *jvm;
    JNIEnv *env;
    
    /*       */
    //disable JIT,  JNI      ,          ,         。
    // JNI              
    options[0].optionString = "-Djava.compiler=NONE";
    //  classpath,           JAR ,           
    options[1].optionString = "-Djava.class.path=.;c:\\";
    //         ,   gc、class jni,                 , -verbose:gc,class
    //         C++  JAVA   ,      ,                    
    options[2].optionString = "-verbose:NONE";
    	
    //     ,    JNI_VERSION_1_1,JNI_VERSION_1_2 JNI_VERSION_1_4
    //         JRE          ,    JRE                 
    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 3;
    vm_args.options = options;
    //               ,   JNI_FLASE,         ,JNI_CreateJavaVM   JNI_ERR
    vm_args.ignoreUnrecognized = JNI_TRUE;
    //  JVM.DLL   
    HINSTANCE hInstance = ::LoadLibrary("C:\\j2sdk1.4.2_15\\jre\\bin\\client\\jvm.dll");
    if (hInstance == NULL)
    {
        return false;
    }
    //     JNI_CreateJavaVM    
    PFunCreateJavaVM funCreateJavaVM = (PFunCreateJavaVM)::GetProcAddress(hInstance, "JNI_CreateJavaVM");
    //  JNI_CreateJavaVM     
    res = (*funCreateJavaVM)(&jvm, (void**)&env, &vm_args);
    if (res < 0)
    {
        return -1;
    }
    //  test.Demo ,  JAVA  CLASS  
    jclass cls = env->FindClass("test/Demo");
    //    CLASS         
    jobject obj = env->AllocObject(cls);
    
    //       ,            ,  javap -s -p        
    jmethodID mid = env->GetMethodID(cls, "append","(Ljava/lang/String;I)Ljava/lang/String;");
    //            
    const char szTest[] = "  ";
    jstring arg = NewJString(env, szTest);
    jstring msg = (jstring) env->CallObjectMethod(obj, mid, arg, 12);
    cout<DestroyJavaVM();
    ::FreeLibrary(hInstance);
    return 0;
}

string  JStringToCString (JNIEnv *env, jstring str)// (jstring str, LPTSTR desc, int desc_len)
{
    if(str==NULL)
    {
        return "";
    }
    // VC wchar_t          (UNICODE)     
    int len = env->GetStringLength(str);
    wchar_t *w_buffer = new wchar_t[len+1];
    char *c_buffer = new char[2*len+1];
    ZeroMemory(w_buffer,(len+1)*sizeof(wchar_t));
    //  GetStringChars   GetStringUTFChars
    const jchar * jcharString = env->GetStringChars(str, 0);
    wcscpy(w_buffer,jcharString);	
    env->ReleaseStringChars(str,jcharString);
    ZeroMemory(c_buffer,(2*len+1)*sizeof(char));
    /          (Win32 API) UNICODE  ASCII       
    len = WideCharToMultiByte(CP_ACP,0,w_buffer,len,c_buffer,2*len,NULL,NULL);
    string cstr = c_buffer;
    delete[] w_buffer;
    delete[] c_buffer;
    
    return cstr;
}

jstring NewJString(JNIEnv *env, LPCTSTR str)
{
    if(!env || !str)
    {
        return 0;
    }
    int slen = strlen(str);
    jchar* buffer = new jchar[slen];
    int len = MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,slen);
    if(len>0 && len < slen)
    {
        buffer[len]=0;
    }
    jstring js = env->NewString(buffer,len);
    delete [] buffer;
    return js;
}

 
3.2 호출 절차 분석 및 주의사항
 
     a. jvm. dll 동적 라 이브 러 리 를 불 러 오고 JNI 가 져 오기CreateJavaVM 함수.이 절 차 는 VC 프로젝트 의 LINK 탭 에 jvm. lib 에 대한 연결 을 추가 한 다음 환경 변수 에 jvm. dll 이 있 는 경 로 를 추가 하여 실현 할 수 있다.하지만 뒤의 이런 방법 은 배치 할 때 이전 방법 보다 번 거 로 울 수 있다.
     b 、 구조 가 좋 은 인 자 를 이용 하여 JNI 호출CreateJavaVM 함수 가 JVM 을 만 듭 니 다.JNI_CreateJavaVM 함수 내 부 는 jvm. dll 의 경로 에 따라 JRE 환경 을 자동 으로 가 져 옵 니 다. 따라서 jvm. dll 파일 을 다른 곳 으로 복사 한 다음 LoadLibrary 함 수 를 통 해 가 져 오지 마 십시오.
     c 、 JVM 생 성 성공 후 JNICreateJavaVM 함 수 는 JNI 컨 텍스트 환경 대상 (JNIEnv) 을 전달 합 니 다. 이 대상 의 관련 함 수 를 이용 하여 JAVA 류 의 속성 과 방법 을 호출 할 수 있 습 니 다.
     d. 위의 코드 를 예 로 들 면 JNIEnv 의 FindClass 방법 을 먼저 호출 합 니 다. 이 함 수 는 하나의 매개 변 수 를 입력 합 니 다. 이 매개 변 수 는 자바 류 의 전역 패키지 이름 의 이름 입 니 다. 예 를 들 어 위의 예제 에서 test / demo 는 test 패키지 의 Demo 류 를 표시 합 니 다.이 방법 은 JVM 을 만 들 때 설정 한 classpath 경로 에서 해당 하 는 클래스 를 찾 습 니 다. 찾 으 면 클래스 대상 으로 돌아 갑 니 다.Class 는 JAVA 의 한 종류 로 모든 JAVA 류 는 유일한 정적 Class 대상 이 있 고 Class 대상 은 클래스 에 관 한 정 보 를 포함 합 니 다.FindClass 방법 으로 클래스 를 찾 을 수 있 도록 JVM 을 만 들 때 - Djava. class. path = 매개 변수 설정 이 올 바른 지 확인 하 십시오.메모: 시스템 환경 변수 중의 CLASSPATH 는 여기에서 JVM 을 만 드 는 데 영향 을 주지 않 습 니 다. 따라서 시스템 CLASSPATH 가 관련 경 로 를 설정 했다 고 생각 하지 마 십시오.
     e. FindClass 가 되 돌아 오 는 class 대상 을 이용 하여 GetMethodID 함 수 를 호출 하면 안에 있 는 방법의 ID 를 얻 을 수 있 습 니 다. 여기 서 GetMethodID 함수 에 세 개의 인자 가 들 어 왔 습 니 다. 첫 번 째 매개 변 수 는 class 대상 입 니 다. 방법 은 특정한 클래스 에 속 하기 때 문 입 니 다.두 번 째 매개 변 수 는 방법의 이름 입 니 다.세 번 째 매개 변 수 는 방법의 서명 입 니 다. 이 서명 은 앞의 3.3 에서 소개 한 방법 으로 얻 을 수 있 습 니 다.
     f. class 대상 을 이용 하여 AllocObject 함 수 를 호출 하여 이 class 대상 이 대응 하 는 클래스 의 인 스 턴 스, 즉 Demo 류 의 대상 을 얻 을 수 있 습 니 다.
     g. 위 에서 가 져 온 함수 ID 와 Demo 류 의 대상 을 이용 하여 CallObject Method 함 수 를 통 해 해당 하 는 방법 을 호출 할 수 있 습 니 다. 이 함수 의 매개 변 수 는 printf 함수 의 매개 변수 와 마찬가지 로 개 수 는 정 해 지지 않 습 니 다.첫 번 째 매개 변 수 는 클래스 의 대상 입 니 다.두 번 째 매개 변 수 는 호출 할 방법의 ID 입 니 다.뒤의 매개 변 수 는 호출 된 JAVA 클래스 방법 에 전달 해 야 하 는 매개 변수 입 니 다. 호출 된 JAVA 클래스 방법 에 매개 변수 가 없 으 면 CallObject Method 를 호출 할 때 앞의 두 매개 변 수 를 전달 하면 됩 니 다.
     h. 위의 예제 에서 볼 수 있 듯 이 JAVA 를 호출 하 는 방법 전에 들 어 오 는 문자열 을 구성 할 때 NewJString 함 수 를 사 용 했 습 니 다.이 방법 을 호출 한 후 전 송 된 문자열 에 JstringToCString 함 수 를 호출 했 습 니 다.이것 은 자바 의 모든 문자 가 유 니 코드 인 코딩 이기 때 문 입 니 다. 그러나 로 컬 방법 에 서 는 VC 로 작 성 된 프로그램 과 같은 특별한 정의 가 없 으 면 유 니 코드 인 코딩 방식 을 사용 하지 않 습 니 다.로 컬 방법 이 자바 에서 정의 하 는 중국어 문자 와 자바 가 로 컬 방법 으로 만 든 중국어 문자열 에 접근 할 수 있 도록 서로 변환 하 는 두 가지 방법 을 정의 했다.
     i. 호출 된 JAVA 클래스 에서 정적 final 멤버 변 수 를 사용 하지 마 십시오. C + + 에서 JAVA 클래스 의 대상 을 생 성 할 때 정적 final 멤버 변 수 는 JAVA 에서 new 대상 처럼 먼저 값 을 부여 하지 않 기 때 문 입 니 다.이러한 상황 이 발생 하면 C + + 에서 이 대상 을 호출 하 는 방법 을 사용 할 때 이 대상 의 정적 final 구성원 변수 값 이 모두 0 또는 null (구성원 변수의 유형 에 따라 정 해 짐) 인 것 을 발견 할 수 있 습 니 다.
 
3.3 JAVA 의 정적 방법 호출
 
//      
jclass cls = env->FindClass("test/Demo");
jmethodID mid = env->GetStaticMethodID(cls, "getHelloWorld","()Ljava/lang/String;");
jstring msg = (jstring)env->CallStaticObjectMethod(cls, mid);	
cout< 
 

 

3.4 JAVA

 

//      
jclass cls = env->FindClass("test/Demo");
jfieldID fid = env->GetStaticFieldID(cls, "COUNT","I");
int count = (int)env->GetStaticIntField(cls, fid);	
cout<   
 

3.5 JAVA

 

//      
jclass cls = env->FindClass("test/Demo");
jmethodID mid = env->GetMethodID(cls,"","(Ljava/lang/String;)V");
const char szTest[] = "  ";
jstring arg = NewJString(env, szTest);
jobject demo = env->NewObject(cls,mid,arg);
//        
mid = env->GetMethodID(cls, "getMessage","()Ljava/lang/String;");
jstring msg = (jstring)env->CallObjectMethod(demo, mid);	
cout< 
 

 

3.6

 

//      
//    
long		arrayCpp[] = {1,3,5,7,9};
jintArray array = env->NewIntArray(5);
env->SetIntArrayRegion(array, 0, 5, arrayCpp);
//    
jclass cls = env->FindClass("test/Demo");
jobject obj = env->AllocObject(cls);
jmethodID mid = env->GetMethodID(cls,"setCounts","([I)V");
env->CallVoidMethod(obj, mid, array);
//    
mid = env->GetMethodID(cls,"getCounts","()[I");
jintArray msg = (jintArray)env->CallObjectMethod(obj, mid, array);
int len =env->GetArrayLength(msg);
jint* elems =env-> GetIntArrayElements(msg, 0);
for(int i=0; i< len; i++)
{
    cout<ReleaseIntArrayElements(msg, elems, 0);

 
3.7 이상 처리     자바 의 방법 을 호출 했 기 때문에 JAVA 함수 가 되 돌아 오 는 이상 이나 JNI 방법 (예: GetMethodID) 을 호출 할 때 던 지 는 이상 이 발생 할 수 있 습 니 다.이러한 이상 은 C + + 자체 의 이상 처리 메커니즘 을 통 해 포착 할 수 없 지만 JNI 는 일부 함 수 를 통 해 자바 에서 던 진 이상 정 보 를 얻 을 수 있다.
//    
jclass cls = env->FindClass("test/Demo");
jobject obj = env->AllocObject(cls);
jmethodID mid = env->GetMethodID(cls,"throwExcp","()V");
env->CallVoidMethod(obj, mid);
//      
string exceptionInfo = "";
jthrowable excp = 0;
excp = env->ExceptionOccurred();	
if(excp)
{
    jclass cls = env->GetObjectClass(excp);
    env->ExceptionClear();
    jmethodID mid = env->GetMethodID(cls, "toString","()Ljava/lang/String;");
    jstring msg = (jstring) env->CallObjectMethod(excp, mid);
    out<ExceptionClear();
}
 
 
 
다 중 스 레 드
 
4.1 다 중 스 레 드 중 주의사항
 
    JNIEnv 와 jobject 대상 은 스 레 드 를 넘 어 사용 할 수 없습니다.
 
    jobject 에 대한 해결 방법 은?
    a、m_obj = m_env->NewGlobalRef(obj);//전역 변수 만 들 기 
    b、jobject obj = m_env->AllocObject(m_cls);//모든 스 레 드 에 대상 을 생 성 합 니 다.
 
    JNIEnv 에 대해 해결 방법 은 모든 스 레 드 에서 env 를 다시 만 드 는 것 입 니 다.
 
    JNIEnv *env;  
    m_jvm->AttachCurrentThread((void **)&env, NULL);  

좋은 웹페이지 즐겨찾기