180 likes | 553 Views
20 장 JNI (Java Native Interface). 김 대 성 2002.1.21 yalli2@freechal.com http://www.jabook.org. 1. JNI 란 ?. 20.1 JNI 란 ?. Java Native Interface 다른 언어로 작성된 프로그램을 자바에서 실행할 수 있게 연결해주는 인터페이스 JNI 의 장점과 단점 장점 자바에서 구현할 수 없는 기능을 구현하게 해줌 각 언어의 장점을 이용할 수 있음 단점 플랫폼의 독립성을 잃어버림
E N D
20장 JNI(Java Native Interface) 김 대 성 2002.1.21 yalli2@freechal.com http://www.jabook.org
1. JNI란? 20.1 JNI란? • Java Native Interface • 다른 언어로 작성된 프로그램을 자바에서 실행할 수 있게 연결해주는 인터페이스 • JNI의 장점과 단점 • 장점 • 자바에서 구현할 수 없는 기능을 구현하게 해줌 • 각 언어의 장점을 이용할 수 있음 • 단점 • 플랫폼의 독립성을 잃어버림 • 플랫폼이 바뀌면 코드의 재사용성도 잃어버림 • 언어별 데이터 형의 차이를 일일이 수정해야함 • 여기서는 언급이 안된 예외처리부분도 신경을 써야함
2. 기초 JNI 예제 20.2 기초 JNI 예제 • JNI 실행 순서 • 먼저 Static블록에 있는 loadLibrary()메서드가 실행 • helloworld.dll 로딩 • main()메서드 실행 • printHelloWorld()메서드 호출 • 자바가상머신은 Helloworld.dll을 통해 C에서 생성한 프로그램 실행 • printf()메서드 실행하여 자바로 리턴 • 도스창에 Hello World! 출력 • main()메서드 종료
public class HelloWorld{ static{ System.loadLibrary(“helloworld"); } public native void printHelloWorld(); public static void main(String[] args) throws Exception{ new HelloWorld().printHelloWorld(); } } 2. 기초 JNI 예제 1단계 • public static void loadLibrary(String labname); • C언어로 만들어진 dll파일을 로딩하는 역할 • Native 메서드가 호출되면 바로 실행하기 위해 사용 HelloWorld.java (라이브러리를 포함하는 자바 파일) 결과화면> C:\20>javac HelloWorld.java public native void printHelloWorld(); • native키워드 • 컴파일러에게 이 메서드의 구현은 외부의 다른 언어로 구현됨을 암시 System.loadLibrary(“helloWorld”);
2. 기초 JNI 예제 2단계 • 1단계에서 작성한 자바파일을 컴파일 • 다른 객체들이 Native메서드를 호출할 수 있도록 하기 위해 C:\20>javac HelloWorld.java
2. 기초 JNI 예제 3단계 • JVM이 사용할 헤더파일 생성 • JVM이 native메서드를 실행하기 위해 helloworld.dll의 헤더파일 생성 • 이 헤더파일을 통해서 C에서 작성된 helloworld.dll을 찾음 • 이 헤더파일은 C에서 사용하는 방법으로는 만들 수 없음 • 헤더파일의 내용 • HelloWorld클래스에서 선언한 printHelloWorld()메서드의 원형이 C의 문법으로 정의되어 있음 • 헤더파일 생성방법 ㅡ> javah 자바파일명 • Jdk안에 포함되어 있다. C:\20>javah HelloWorld
#include <jni.h> #include “HelloWorld.h” #include <stdio.h> JNIEXPORT void JNICALL Java_HelloWorld_printHelloWorld (JNIEnv * env, jobject obj){ printf(“Hello World!\n”); return; } HelloWorld.c (native메서드를 실행할 C소스) 2. 기초 JNI 예제 4단계 • C언어로 Native Method생성 • 자바에서 printHelloWorld()메서드를 호출하면 C의 printf()함수가 실행 • 반드시 jni.h, HelloWorld.h, stdio.h 헤더 파일을 include 할 것
2. 기초 JNI 예제 5단계 • helloworld.dll 작성 • C 파일과 헤더 파일을 사용하여 helloworld.dll 생성 • -Ic:\jdk1.3.1\include: jni.h의 경로 • -Ic:\jdk1.3.1\include\win32 : jni_md.h의 경로 • -LD HelloWorld.c:컴파일할 c파일명 • -Fehelloworld.dll:생성할 dll파일명 • 반드시 loadLibrary()메서드에 주었던 매개변수명과 일치할 것 C:\20>cl -Ic:\jdk1.3.1\include -Ic:\jdk1.3.1\include\win32 -LD HelloWorld.c -Fehelloworld.dll HelloWorld.c /dll /implib:helloworld.lib /out:helloworld.dll HelloWorld.obj Creating library helloworld.lib and object helloworld.exp
2. 기초 JNI 예제 6단계 • Java HelloWorld를 실행 • 실행 순서 • 먼저 Static블록에 있는 loadLibrary()메서드가 실행 • helloworld.dll 로딩 • main()메서드 실행 • printHelloWorld()메서드 호출 • 자바가상머신은 Helloworld.dll을 통해 C에서 생성한 프로그램 실행 • printf()메서드 실행하여 자바로 리턴 • 도스창에 Hello World! 출력 • main()메서드 종료 C:\20>java HelloWorld Hello World!
public class Calculator{ static{ System.loadLibrary("calculator"); } public native int add(int a, int b); public static void main(String[] args) throws Exception{ System.out.println(new Calculator().add(10,5)); } } #include <jni.h> #include "Calculator.h" #include <stdio.h> JNIEXPORT jint JNICALL Java_Calculator_add(JNIEnv *env, jobject obj, jint a, jint b){ jint sum; printf(“a+b= ”); sum = a + b; return sum; } Calculator.java (native메서드 생성) Calculator.c (Native Type의 사용의 예) 3. 숫자 인자와 반환값 20.3 숫자 인자와 반환값 • Native Type • 자바와 다른 언어간의 기본형데이터의 차이를 해결하기 위한 방법 • 단순히 java Type 앞에 j를 붙이면 된다. • 예> int -> jint 결과화면> C:\20>javac Calculator.java C:\20>javah Calculator C:\20>cl -Ic:\jdk1.3.1\include -Ic:\jdk1.3.1\include\win32 -LD Calculator.c -Fecalculator.dll C:\20>java Calculator a+b=15
JNIEXPORT jstring JNICALL Java_Prompt_getLine(JNIEnv *env, jobject obj , jstring prompt) { printf("%s", prompt); ... } 잘못된 jstring의 사용 예 4. 문자열 전달 인자 20.4 문자열 전달 인자(1) • 자바와 C언어간의 문자열 데이터타입을 맞춰주기 위해 사용 • 자바에서는 String을 위해 16비트의 Unicode문자세트 사용 • C에서는 일반적으로 8비트의 문자배열로 문자열을 표현 • GetStringUTFChars()메서드를 사용하여 UTF-8문자열로 변경 • UTF-8문자열사용이 끝나면 ReleaseStringUTFChars()메서드로 해제 • 가상머신에게 UTF-8문자열을 더 이상 사용하지 않는다고 알려주는 역할
public class MessageType { static { System.loadLibrary("message"); } public native String printMessage(String str); public static void main(String[] args) throws Exception { MessageType h = new MessageType(); System.out.println(h.printMessage("Type anything? : ")); } } MessageType.java (jstring 사용 예제) 4. 문자열 전달 인자 20.4 문자열 전달 인자(2) 결과화면> C:\20>javac MessageType.java C:\20>javah MessageType
#include <jni.h> #include "MessageType.h" #include <stdio.h> JNIEXPORT jstring JNICALL Java_MessageType_printMessage(JNIEnv* env, jobject obj, jstring msg) { char buf[128]; const char *str = (*env)->GetStringUTFChars(env, msg, 0); printf("%s", str); (*env)->ReleaseStringUTFChars(env, msg, str); scanf("%s", buf); return (*env)->NewStringUTF(env, buf); } MessageType.c (jstring을 사용한 C파일) 4. 문자열 전달 인자 20.4 문자열 전달 인자(3) 1 2 3 자바의 16비트문자열을 C언어의 8바이트 문자열로 변환 가상머신에게 UTF-8문자열의 사용이 끝남을 알리고 메모리에서 자원을 해지 사용자로 부터 입력받은 문자열을 자바의 유니코드로 변환 1 2 3 결과화면> C:\20>cl -Ic:\jdk1.3.1\include -Ic:\jdk1.3.1\include\win32 -LD MessageType.c -Femessage.dll C:\JavaExample\20>java MessageType Type anything? : Hi!jabook Hi!jabook
public class FieldControl { int int_a = 10; double double_b = -1.2345; static { System.loadLibrary("control"); } public native double add(); public static void main(String[] args) throws Exception { double c = new FieldControl().add(); System.out.println("final result ==> a + b = " + c); } } MessageType.java (멤버변수를 생성하는 자바 소스) 5. 객체 변수에 접근하기 20.5 객체 변수에 접근하기(1) • JNI가 제공하는 함수를 사용, 자바 객체의 변수에 접근 • Native 메서드에게 자바의 객체형과 변수의 형과 이름을 알려줄 것 결과화면> C:\20>javac FieldControl.java C:\20>javah FieldControl
#include <jni.h> #include "FieldControl.h" #include <stdio.h> JNIEXPORT jdouble JNICALL Java_FieldControl_add (JNIEnv *env, jobject obj){ double c; jclass class_fieldcontrol = (*env)->GetObjectClass(env, obj); jfieldID id_a = (*env)->GetFieldID(env, class_fieldcontrol, "int_a", "I"); jint a = (*env)->GetIntField(env,obj,id_a); jfieldID id_b = (*env)->GetFieldID(env, class_fieldcontrol, "double_b", "D"); jdouble b = (*env)->GetDoubleField(env,obj,id_b); printf("a : %d \n", a); printf("b : %f \n", b); c= a+b; printf("before ==> a + b = %f \n", a+b); a += 5; (*env)->SetIntField(env, obj, id_a, a); b += 2.123; (*env)->SetDoubleField(env, obj, id_b, b); c= a+b; printf("after ==> a + b = %f \n", a+b); return c; } FieldControl.c (자바의 멤버변수를 조작하는 C언어의 소스코드) 5. 객체 변수에 접근하기 20.5 객체 변수에 접근하기(2) 결과화면> C:\20>cl -Ic:\jdk1.3.1\include -Ic:\jdk1.3.1\include\win32 -LD FieldControl.c -Fecontrol.dll C:\20>java FieldControl a : 10 b : -1.234500 before ==> a + b = 8.765500 after ==> a + b = 15.888500 final result ==> a + b = 15.8885
public class MethodControl { static { System.loadLibrary("control"); } public native void add(); public int multi(int a, int b){ return a*b; } public static void main(String[] args) throws Exception{ new MethodControl().add(); } } MethodControl.java (멤버변수를 생성하는 자바 소스) 6. 객체의 메서드 실행하기 20.6 자바 메서드 실행하기(1) • C에서 자바의 메서드를 호출하는 방법 • 1단계 : 자바 객체 타입 알아오기 • 2단계 : 자바 객체 타입에서 호출하려는 메서드의 식별정보 알아오기 • 3단계 : 메서드의 식별정보를 사용해서 메서드 호출하기 결과화면> C:\20>javac MethodControl.java C:\20>javah MethodControl
#include <jni.h> #include "MethodControl.h" #include <stdio.h> JNIEXPORT void JNICALL Java_MethodControl_add (JNIEnv *env, jobject obj){ jclass class_methodcontrol = (*env)->GetObjectClass(env, obj); jmethodID m_id = (*env)->GetMethodID(env, class_methodcontrol, "multi", "(II)I"); jint c_a, c_b, c_c; c_a = 5; c_b = 10; c_c = (*env)->CallIntMethod(env, obj, m_id, c_a, c_b); printf("c = %d \n", c_c); } 6. 객체의 메서드 실행하기 20.6 자바 메서드 실행하기(2) FieldControl.c (자바의 메서드를 호출하는 C언어의 소스코드) 결과화면> C:\20>cl -Ic:\jdk1.3.1\include -Ic:\jdk1.3.1\include\win32 -LD MethodControl.c -Fecontrol.dll C:\20>java MethodControl c = 50
7. 마무리 20.7 마무리 • JNI • 자바에서 다른 언어로 쓰여진 애플리케이션을 사용할 수 있도록 연결 • JNI의 장점과 단점 • 장점 • 자바에서 구현할 수 없는 기능을 구현하게 해줌 • 각 언어의 장점을 이용할 수 있음 • 단점 • 플랫폼의 독립성을 잃어버림 • 플랫폼이 바뀌면 코드의 재사용성도 잃어버림 • 언어별 데이터 형의 차이를 일일이 수정해야함 • 여기서는 언급이 안된 예외처리부분도 신경을 써야함 • JNI 실행 순서 • 먼저 Static블록에 있는 loadLibrary()메서드가 실행 • helloworld.dll 로딩 • main()메서드 실행 • printHelloWorld()메서드 호출 • 자바가상머신은 Helloworld.dll을 통해 C에서 생성한 프로그램 실행 • printf()메서드 실행하여 자바로 리턴 • 도스창에 Hello World! 출력 • main()메서드 종료