<< index              < bölüm 13                 > bölüm 15                


 

BÖLÜM 14:  JAVA ANADİL (NATIVE LANGUAGE)  PROGRAMLAMASINA GİRİŞ

C++ ve C PROGRAMLAMA DİLLERİNİN JAVA İLE BİRLİKTE KULLANIMI

 

14.1 TEMEL KAVRAMLAR

 

Java programlama dili C dilinde yazılmıştır. Bu yüzden C’den javaya geçiş oldukça kolay bir şekilde yapılabilir. Bir örnekle birden fazla programlama dilinin nasıl kullanılabildiğine bakmadan önce, bir temel kavramı iyi anlamamız gerekir. Java güvenlik açısından maksimum güvenliği verebilen bir dildir. Öte taraftan C maksimum hızlara ulaşmayı sağlayabilen bir dildir. C programlarını java programlarıyla birlikte kullanmamızın temel nedeni hız gereken yerlerde bu hızı sağlamaktır. Ancak hız sağlarken güvenlikten olan kaybımızı her zaman hesaba katmamız ve ikisi arasında bir denge bulmamız biz programcılara bırakılmıştır. Bu yüzden iki dilli programlamada oldukça dikkatli bir şekilde çalışma gereksinimi  oluşturur. Bu konu C++ dilini iyi bilen programcılar içindir. Burada C programlamasına girmeyeceğiz. Eğer bu dili bilmiyorsanız, bu konuya başlamadan önce öğrenmenizi veya java anadil programlamasını hiç kullanmamanızı tavsiye ederim. C++ dilini kullanabilmek için, hele iki dili bir arada kullanabilmek için iyi bir programcı olmanız gerekiyor, eğer kendinizi güveniyorsanız, bundan sonraki kısma geçebilirsiniz.

 

14.2 Örnek problemle step step iki dilli program kodunun hazırlanması ve çalıştırılması

Çok dilli programlama birden fazla basamağı gerektiren bir prosestir. Bir örnek problemler bu basamakları inceleyelim :

 

C++ dili ile java dilinin  beraber çalışacağı bir örnek oluşturalım. İlk step olarak java dilindeki programımızı yazalım :

 

Program 14.1 JavaCpp.java programı

 

class JavaCpp

{

    public native void cdenaktar();

    static

    {

        System.loadLibrary("jcpp");

    }

 

    public static void main(String[] args)

    {

        new JavaCpp().cdenaktar();

    }

}

 

JavaCpp programında iki temel metod görüyoruz. Birinci metod cdenaktar() metodudur. Bu metod biraz sonra C++ dilinde oluşturacağımız fonksiyonu Java’nın bir parçası olarak çağırır. İkinci metod ise main metodudur. Cdenaktar metoduna bakarken bunun java metodu olmadığını belirten native sözcüğü yer almaktadır. Metodun türü void’dir, yani hiçbir şey aktarılmıyacaktır. Programımızı, herhangi bir java programında olduğu gibi önce

java JavaCpp.java

Komutunu kullanarak derleriz. İkinci stepte javah komutunu kullanarak

javah JavaCpp

JavaCpp.h dosyasını oluştururuz. Bu dosyanın içeriği :

 

Program 14.2 JavaCpp.h  arabağlantı programı

 

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class JavaCpp */

 

#ifndef _Included_JavaCpp

#define _Included_JavaCpp

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     JavaCpp

 * Method:    cdenaktar

 * Signature: ()V

 */

JNIEXPORT void JNICALL Java_JavaCpp_cdenaktar

  (JNIEnv *, jobject);

 

#ifdef __cplusplus

}

#endif

#endif


şeklinde olacaktır. Bundan sonraki stepte C++ dilinde aşağıdaki programı oluşturalım :

 

Program 14.3 JavaCpp_c.cpp  C++ programı

 

#include <iostream.h>

#include <jni.h>

#include "JavaCpp.h"

 

JNIEXPORT void JNICALL

Java_JavaCpp_cdenaktar(JNIEnv *env, jobject obj)

{

    cout<<"Java-C++ programlama dillerini birlikte kullanıyoruz ";

    return;

}

 

c++ programını derlemek için elbette bir derleyiciye ihtiyaç vardır. Biz burada MS Visual C++ versiyon 6 derleyicisini kullandık, herhangi bir dll dosyası hazırlayan derleyici (MS Windows için) aynı işi görebilir.

Bu derleyici ile derleme için ya direk olarak dos’ta

 

cl  -Ic:\co\java\include -Ic:\co\java\include\win32 -LD %JavaCpp_c.cpp –Fejcpp.dll

 

 

komutunu kullanırız, yada bu uzun komutu her sefer yazmamak için bir isim.bat dosyası yaratıp bunu kullanabiliriz. Örneğin hazırladığımız pcomp.bat dosyası

 

Program 14.4 pcomp.bat MSdos programı

cl  -Ic:\co\java\include -Ic:\co\java\include\win32 -LD %1.cpp -Fe%2.dll

 

kullanılarak yukarıdaki komut

pcomp JavaCpp_c  jcpp

 

şeklinde verilebilir. Bu işlemleri yaptığımızda programımız çalışmaya hazır olacaktır. Programı çalıştırmak için :

java JavaCpp

komutunu kullanmamız yeterli olacaktır. Program çıktısı :

 

Java-C++ programlama dillerini birlikte kullanıyoruz

 

Şeklinde olacaktır. Burada derlemenin jcpp.dll dosyasına yapıldığını hatırlatalım, ve bu dosya java programı üzerinden C++ metodunu çalıştırırken kullandığımız ana programdı.

 

14.2 DEĞİŞKENLERİN VE JAVA NESLERİNİN AKTARILMASI

 

İlk programımızda java ve C++ arasında herhangi bir değişken aktarılması olmamış, sadece void türü fonksiyon kullanılarak belli bir yazı yazan C++ fonksiyonu çağırılmıştır. İkinci örneğimizde java programımızdan String türü değişkeni C++ programlama diline aktaracak ve kullanacağız.

 

İlk java programımız Showmessage.java. bu programda ekrandan girilen bir string, yahut ekrandan girilen bir string değeri yoksa programın içinde tanımlanan bir stringle birlikte C++ programına aktarılıp burada ekrana yazılmaktadır.

 

Program 14.5 ShowMessage.java programı

 

public class ShowMessage {

private native void ShowMessage(String msg);

static { System.loadLibrary("MsgI"); }

 

public static void main(String[] args) {

ShowMessage app = new ShowMessage();

if(args.length==0)

  app.ShowMessage("Bu mesaj javadan C++ ya gönderildi ve orada yazıldı");

else

  app.ShowMessage(args[0]);

}

}

 

bu program javac ShowMessage.java ve javah ShowMessage komutlarıyla işlendikten sonra

 

Program 14.6 MsgImpl.cpp programı

 

//dosya : MsgImpl.cpp

#include <jni.h>

#include <iostream.h>

#include <stdio.h>

#include "ShowMessage.h"

extern "C" JNIEXPORT void JNICALL

Java_ShowMessage_ShowMessage(JNIEnv* env,

jobject, jstring jMsg)

{

const char* msg=env->GetStringUTFChars(jMsg,0);

printf("JNI cikti stringi : %s\n",msg) ;

env->ReleaseStringUTFChars(jMsg, msg);

}

 

c++ dilindeki MsgImpl.cpp programı hazırlanmış ve

üstte hazırladığımız pcomp.bat yardımıyla

 

pcomp MsgImpl MsgI

 

komutu kullanılarak derlenmiştir. Program çıktısı

 

java ShowMessage “Merhaba Dünya” komutu kullanılarak :

JNI cikti stringi : Merhaba Dünya

veya

java ShowMessage komutu kullanılarak

JNI cikti stringi : Bu mesaj javadan C++ ya gönderildi ve orada yazdırıldı

Çıktısı alınabilir. Programda veri aktarımı yapmak amacıyla java tarafında metod tanımı yapılırken

private native void ShowMessage(String msg);

tanımı verilmiştir. Buradaki String msg metodun dolayısıyla C++ fonksiyonunun girdisini teşkil etmektedir. C++ tarafında mesajı alırken,

 

Java_ShowMessage_ShowMessage(JNIEnv* env,

jobject, jstring jMsg)

{

const char* msg=env->GetStringUTFChars(jMsg,0);

 

jstring jMsg tanımıyla aktarılmış ve const char* msg=env->GetStringUTFChars(jMsg,0);

tanımıyla c değişkenine dönüştürülmüştür.

Javada Stringler unicode (16 bit) olarak tanımlanmıştır. C stringleri ise 8 bitlik ascii char boyutlu değişkeni olarak tanımlanır. Bu yüzden string değişkenlerini javadan cye veya cden javaya aktarırken dönüşümler yapmak gerekir. Aynı zamnda java string değişkenleri length (boyut) değişkenini de bünyelerinde taşırlar. Cde ise boyut tanımlanmamıştır. Ayrı bir değişken üzerinden tanımlanması gerekebilir. Bu dönüşümleri yapmak için bir dizi metod tanımlanmıştır.

Bu tanımaların tamamı şöyledir :

 

    GetStringChars

    GetStringLength

    GetStringUTFChars

    GetStringUTFLength

    NewString

    NewStringUTF

    ReleaseStringChars

    ReleaseStringUTFChars

 

Buradaki ikinci örneğimizde java programında c++ dilindeki bir fonksiyonun (metod) yaptığı hesap sonuçlarını aktaracağız. Programımız java’da çağırılan bir C++ kare metodunu kullanarak java dilinde girilen sayının karesini hesaplayacaktır.

 

Program 14.7 karesinifi.java programı

 

class karesinifi {

  private native double kare(double x);

  public static void main(String args[]) {

    karesinifi p = new karesinifi();

    double x=2.0;

    double y = p.kare(x);

    System.out.println("" +x+" kare = "+ y);

  }

  static {

    System.loadLibrary("kareI");

  }

}

 

bu programı javac karesinifi.java deyimiyle derleyip, javah karesinifi deyimiyle anadil kütüphanesine çevirirsek

 

Program 14.8 karesinifi.h programı

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class karesinifi */

 

#ifndef _Included_karesinifi

#define _Included_karesinifi

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     karesinifi

 * Method:    kare

 * Signature: (D)D

 */

JNIEXPORT jdouble JNICALL Java_karesinifi_kare

  (JNIEnv *, jobject, jdouble);

 

#ifdef __cplusplus

}

#endif

#endif

 

karesinifi.h bize java programındaki

  private native double kare(double x);

metodunun c++ anadil (Native) karşılığının

JNIEXPORT jdouble JNICALL Java_karesinifi_kare

  (JNIEnv *, jobject, jdouble);

olduğunu göstermektedir. Şimdi kare metodunun aslını C++ dilinde yazarsak :

 

Program 14.9 karesinifi.cpp  C++ programı

 

#include <stdio.h>

#include <jni.h>

#include "karesinifi.h"

 

JNIEXPORT jdouble JNICALL Java_karesinifi_kare(JNIEnv *, jobject, jdouble x )

{

  return x*x;

}

 

burada metod isminin kare yerine Java_karesinifi_kare şeklini aldığını görüyoruz. Double değişkeni de yerini jdouble değişkenine bırakmış durumda. Java anadilinde  programları yazarken metod isimleri

Java_sınıfismi_metodismi

Şeklini alır. Basit java değişkenlerinin Anadil karşılıkları ise

 

Tablo 14.1    Java değişken tipleri ve ana dil (native) eşdeğerleri

Java değişken tipi

Anadil (Native) değişken eşdeğeri

Değişken bit değeri

         Boolean

                 jboolean

8, işaretsiz

         Byte

                 jbyte

8

         Char

                 jchar

16, işaretsiz

         Short

                 jshort

16

         Int

                 jint

32

         Long

                 jlong

64

         Float

                 jfloat

32

         Double

                 jdouble

64

        Object

                 jobject

 

         Void

                 void

Yok

 

Şeklindedir. C++ programı

pcomp karesinifi kareI

deyimiyle veya açık yazılışıyla

cl  -Ic:\co\java\include -Ic:\co\java\include\win32 -LDkaresinifi.cpp –KareI.dll

deyimiyle derlenirse (MS Visual C++ 6), sonuç :

2.0 kare = 4.0

şeklinde çıkacaktır.

  

Şimdi de bu işlemin tam tersini inceleyelim. Java’da yazılmış olan kare metodunu C++ ve C dillerinde çağıralım.

 

Java programımız karesinifi1.java aşağıdaki gibi tanımlanmıştır.

 

Program 14.10 karesinifi1.java  java programı

 

class karesinifi1 {

  private native void nativeMethod();

  private double kare(double x)

  {

  return x*x;

  }

  public static void main(String args[])

  {

  karesinifi1 c=new karesinifi1();

  c.nativeMethod();

  }

  static {

    System.loadLibrary("kare1I");

  }

}

 

sınıfın alt sınıfı olan kare’de girilen sayının karesi hesaplanmaktadır. NativeMethod metodu da C (veya c++) dilleriyle bağlantı sağlamaktadır. Metodumuzu yine java karesinifi1.java ile derledikten sonra javah karesinifi1 komutuyla karesinifi1.h dosyasını oluştururuz. Bu dosya :

 

Program 14.11 karesinifi1.h   programı

 

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class karesinifi1 */

 

#ifndef _Included_karesinifi1

#define _Included_karesinifi1

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     karesinifi1

 * Method:    nativeMethod

 * Signature: ()V

 */

JNIEXPORT void JNICALL Java_karesinifi1_nativeMethod

  (JNIEnv *, jobject);

 

#ifdef __cplusplus

}

#endif

#endif

 

anadil tarafında program yazılırken bize yardımcı olabilecek bir ara java programı javap de mevcuttur.

Bu işlemi yapmak zorunda değiliz. Yapma sebebimizi c++ dili programını inceleyince daha iyi anlayacaksınız.

 

javap -s -p karesinifi1

 

Program 14.12 javap komutuyla oluşturulan ara kod

 

Compiled from karesinifi1.java

class karesinifi1 extends java.lang.Object {

    karesinifi1();

                /*   ()V   */

    private native void nativeMethod();

                /*   ()V   */

    private double kare(double);

                /*   (D)D   */

    public static void main(java.lang.String[]);

                /*   ([Ljava/lang/String;)V   */

    static {};

                /*   ()V   */

}

 

şimdi c++ koduna bakalım :

 

Program 14.13 karesinifi1.cpp programı

 

#include <stdio.h>

#include <iostream.h>

#include <jni.h>

#include "karesinifi1.h"

 

JNIEXPORT void JNICALL Java_karesinifi1_nativeMethod(JNIEnv *env, jobject obj)

{

   jclass cls=env->GetObjectClass(obj);

   jmethodID mid=env->GetMethodID(cls,"kare","(D)D");

   double x=2.0;

   double y=env->CallDoubleMethod(obj,mid,x);

   cout<<x<<"nin karesi = "<<y;

}

 

Bu programda önce java sınıfının (karesinifi1) aktarılması jobject obj değişkeni ve  

jclass cls=env->GetObjectClass(obj);

üzerinden yapılır. Burada sınıf adresi cls değişkenine yüklenmiş olur. Alt metod karenin tanımı için

jmethodID mid=env->GetMethodID(cls,"kare","(D)D");

tanımı kullanılmıştır. Buradaki “(D)D” tanımı program 14.12 de bize verilmişti. Anlamı java programındaki kare metodunun double değişken girişi olduğu ve çıkışında double değişken istediğidir. “kare” deyimiyle metodun javadaki ismi verilmiştir. Cls ise üstte tanımladığımız karesinifi1 java sınıfının adresine belirtmektedir.

   double y=env->CallDoubleMethod(obj,mid,x);

deyimiyle de metodu çağırıp sonuçlarını y değişkenine yüklemekteyiz.

Burada kullandığımız D işareti java değişken türünün double olduğunu belirtiyordu. Java değişken tiplerinin işaret karşılıkları Tablo 14.2 de verilmiştir.

 

Tablo 14.2 Java tiplerinin eşdeğer işaretleri

İşaret

Java değişken tipi

  Z

                     boolean

 B

                     Byte

 C

                     Char

 S

                     Short

 I

                     Int

 J

                     Long

 F

                     Float

 D

                     Double

 L sınıf ismi

                     sınıf ismi

 [Değişken türü

                     Değişken türü[]

 

Bu programda sınıfı çağırmak için GetObjectClass metodu, metodu tanımlamak içinde GetMethodID metodunu kullandık. CallDoubleMethod metodu ile de metodu çalıştırdık. Paralel işlemleri yapmak için mevcut olan metod listesi ve anlamları şöyledir :

 

    GetObjectClass : sınıf adresini tanımlar

    GetMethodID : dinamik metod adresini tanımlar

    GetStaticMethodID : statik metod adresini tanımlar

    Call<değişkentürü>Method : çeşitli metodları çağırır

        CallBooleanMethod

        CallByteMethod

        CallCharMethod

        CallDoubleMethod

        CallFloatMethod

        CallIntMethod

        CallLongMethod

        CallObjectMethod

        CallShortMethod

        CallVoidMethod

        CallStatic< değişkentürü >Method : statik metodları çağırır, değişken türleri olarak yukaridakinin aynı 

        türleri kabul eder.

    CallNonvirtual< değişkentürü >Method

    Call< değişkentürü >MethodV 

    Call< değişkentürü >MethodA

Aynı programın c dilinde yazılması küçük farklılıklar taşır. C dilideki program :

 

Program 14.14 karesinifi1.c programı

 

#include <stdio.h>

#include <jni.h>

#include "karesinifi1.h"

 

JNIEXPORT void JNICALL Java_karesinifi1_nativeMethod(JNIEnv *env, jobject obj)

{

   jclass cls=(*env)->GetObjectClass(env,obj);

   jmethodID mid=(*env)->GetMethodID(env,cls,"kare","(D)D");

   double x=2.0;

   double y=(*env)->CallDoubleMethod(env,obj,mid,x);

   printf("%f nin karesi = %f ",x,y);

}

 

programdan da görüldüğü gibi  C++ daki :

   jclass cls=env->GetObjectClass(obj);

komutu

   jclass cls=(*env)->GetObjectClass(env,obj);

halini almıştır.

   jmethodID mid=env->GetMethodID(cls,"kare","(D)D");

komutu

   jmethodID mid=(*env)->GetMethodID(env,cls,"kare","(D)D");

halini almıştır.

   double y=env->CallDoubleMethod(obj,mid,x);

komutu ise

   double y=(*env)->CallDoubleMethod(env,obj,mid,x);

halini almıştır. Sonuç olarak env yerine referans değişkeni (*env) gelmektedir ve env referans değişkeni aynı zamanda metod değişkeni olarakda çağırılmaktadır. Bunun dışında işlemler arasında bir fark yoktur.

Program java karesinifi1 deyimiyle çalıştırıldığında

2nin karesi = 4

sonucunu alırız.

 

İkinci bir sınıf  ulaşım örneği olarak UseObjects programını verelim. Burada sınıf, MyJavaClass içinde bir int değişken ve bir void metod mevcuttur. İkinci bir metod olan UseObjects metodu kullanılarak native metod changeObject’e ulaşılmakta ve bu metod c++ programında kullanılarak sonuçlar hesaplanmaktadır.

 

Program 14.15 UseObjects.java programı

 

//UseObjects.java

class MyJavaClass {

public int aValue;

public void divByTwo() { aValue /= 2; }

}

public class UseObjects {

private native void

changeObject(MyJavaClass obj);

static {

System.loadLibrary("UseObjImpl");

}

public static void main(String[] args) {

UseObjects app = new UseObjects();

MyJavaClass anObj = new MyJavaClass();

anObj.aValue = 2;

app.changeObject(anObj);

System.out.println("Java: " + anObj.aValue);

}

}

 

Program 14.16 javah UseObject komutu kullanılarak oluşturulan UseObjects.h programı

 

/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class UseObjects */

 

#ifndef _Included_UseObjects

#define _Included_UseObjects

#ifdef __cplusplus

extern "C" {

#endif

/*

 * Class:     UseObjects

 * Method:    changeObject

 * Signature: (LMyJavaClass;)V

 */

JNIEXPORT void JNICALL Java_UseObjects_changeObject

  (JNIEnv *, jobject, jobject);

 

#ifdef __cplusplus

}

#endif

#endif

 

Program 14.17 UseObjImp.cpp programı

#include <jni.h>

extern "C" JNIEXPORT void JNICALL

Java_UseObjects_changeObject( JNIEnv* env, jobject, jobject obj)

{

jclass cls = env->GetObjectClass(obj);

jfieldID fid = env->GetFieldID(cls, "aValue", "I");

jmethodID mid = env->GetMethodID(cls, "divByTwo", "()V");

int value = env->GetIntField(obj, fid);

printf("Native: %d\n", value);

env->SetIntField(obj, fid, 6);

env->CallVoidMethod(obj, mid);

value = env->GetIntField(obj, fid);

printf("Native: %d\n", value);

}

 

Program 14.15 de tanımlanan MyJavaClass sınıfı bir int değişken, aValue,  ve bir metod, divByTwo , içermektedir. Metod int de verilen değeri 2 ye bölmekte ve sonucu aktarmaktadır. Bu programda int sınıf alt değişkenini tanımlamak için

jfieldID fid = env->GetFieldID(cls, "aValue", "I");

deyimini kullandık. Void aValue metodu

jmethodID mid = env->GetMethodID(cls, "divByTwo", "()V");

deyimiyle tanımlandı. Ve

env->SetIntField(obj, fid, 6);

tanımıyla 6 değeri atandı.

Sınıfların alt değişkenlerine değer atamak (ve okumak )için

    GetFieldID

    GetStaticFieldID

    Get< değişkentürü >Field

        GetBooleanField

        GetByteField

        GetCharField

        GetDoubleField

        GetFloatField

        GetIntField

        GetLongField

        GetObjectField

        GetShortField

    Set< değişkentürü >Field

    GetStatic< değişkentürü >Field

    SetStatic< değişkentürü >Field

Metodları mevcuttur.

 

Şimdi de Çok boyutlu değişkenleri nasıl kullanabildiğimizi inceleyelim :

 

Program 14.18 IntArray.java programı

 

class IntArray {

  private native int sumArray(int arr[]);

  public static void main(String args[]) {

    IntArray p = new IntArray();

    int arr[] = new int [10];

    for (int i = 0; i < 10; i++)

      arr[i] = i;

    int sum = p.sumArray(arr);

    System.out.println("sum = " + sum);

  }

  static {

    System.loadLibrary("MyImpOfIntArray");

  }

}

 

 

Program 14.19 IntArray.c programı

 

#include <jni.h>

#include "IntArray.h"

 

JNIEXPORT jint JNICALL

Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)

{

  jsize len = (*env)->GetArrayLength(env, arr);

  int i, sum = 0;

  jint *body = (*env)->GetIntArrayElements(env, arr, 0);

  for (i=0; i<len; i++) {

    sum += body[i];

  }

  (*env)->ReleaseIntArrayElements(env, arr, body, 0);

  return sum;

}

 

burada tanımlanan java programında boyutlu değişken arr tanımlanmış, ve boyutlu değişkenin toplamı c programında hesaplanmıştır. C metodunda boyutlu değişkeni tanımlamak için jintArray türü arr değişkeni kullanılmıştır. Boyutlu değişkenin boyutu jsize tipi len değişkenine

  jsize len = (*env)->GetArrayLength(env, arr);

deyimiyle aktarılmıştır.

arr değişkeninin değeri jint tipi body boyutlu değişkene, indeksi 0dan başlamak üzere

  jint *body = (*env)->GetIntArrayElements(env, arr, 0);

metoduyla aktarılır.

arr boyutlu değişkeninin değeri (değerler değişmişte olabilir) tekrar kullanılabilmek üzere

   (*env)->ReleaseIntArrayElements(env, arr, body, 0);

deyimi kullanılarak serbest bırakılır (javaya gönderilir). Bu işlemlerin sonucunda java programı :

sum = 45

 

sonucunu verecektir. JNI boyutlu değişken çağırma fonksiyonları(metodları) şöyledir :

 

    GetArrayLength

    Get< değişkentürü >ArrayElements

        GetBooleanArrayElements

        GetByteArrayElements

        GetCharArrayElements

        GetDoubleArrayElements

        GetFloatArrayElements

        GetIntArrayElements

        GetLongArrayElements

        GetShortArrayElements

    Release< değişkentürü >ArrayElements

    Get< değişkentürü >ArrayRegion

    Set< değişkentürü >ArrayRegion

    GetObjectArrayElement

    SetObjectArrayElement

 

Java dilinde tanımlanmış, fakat c dilinde direk tanımlanmamış işlemlerden birisi de hata analiz işlemidir (Catch-throw exception). Ana dil programlaması kullanırken, bu işlemi de yapmak mümkündür. Aşağıdaki CatchThrow program setinde hata sisteminin kullanılmasını görüyoruz.

 

Program 14.20 CatchThrow.java programı

 

class CatchThrow {

  private native void catchThrow() throws IllegalArgumentException;

  private void callback() throws NullPointerException {

    throw new NullPointerException("thrown in CatchThrow.callback");

  }

  public static void main(String args[]) {

    CatchThrow c = new CatchThrow();

    try {

      c.catchThrow();

    } catch (Exception e) {

      System.out.println("In Java:\n  " + e);

    }

  }

  static {

    System.loadLibrary("MyImpOfCatchThrow");

  }

}

 

Program 14.21 CatchThrow.c programı

 

#include <jni.h>

#include "CatchThrow.h"

 

JNIEXPORT void JNICALL

Java_CatchThrow_catchThrow(JNIEnv *env, jobject obj)

{

  jclass cls = (*env)->GetObjectClass(env, obj);

  jmethodID mid = (*env)->GetMethodID(env, cls, "callback", "()V");

  jthrowable exc;

  if (mid == 0) {

    return;

  }

  (*env)->CallVoidMethod(env, obj, mid);

  exc = (*env)->ExceptionOccurred(env);

  if (exc) {

    /*

  Biz aslında c’de hata konusunda gerçekten bir şey yapmıyoruz,

  sadece bir mesaj iletiyoruz, hata değişkenini temizliyoruz ve

   yeni bir exception gönderiyoruz. */

    jclass newExcCls;

 

    (*env)->ExceptionDescribe(env);

    (*env)->ExceptionClear(env);

 

    newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");

    if (newExcCls == 0) { /* Unable to find the new exception class, give up. */

      return;

    }

    (*env)->ThrowNew(env, newExcCls, "thrown from C code");

  }

}

 

bu programı çalıştırdığımızda :

 

 

sonucunu alırız. Buradaki

In Java:

  java.lang.IllegalArgumentException: thrown from C code

mesajı c tarafından oluşturulup gönderilmiştir.

 

JNI Hata fonksiyonları şunlardır :

 

    ExceptionClear

    ExceptionDescribe

    ExceptionOccurred

 

Burada iki dilli programlama kavramına bir giriş yaptık. Buradaki kavramlar size biraz zor geldiyse lütfen umutsuzluğa kapılmayın, java ve C dillerini çok iyi öğrendikten sonra geri dönün. İki dilli programlama her zaman programlama dünyasının en zor işlerindendir, ayrıca jbuilder, Microsoft j++ gibi paketler java anadil (native) programlamasında işleri kolaylaştıran otomatik kod oluşturma sisyemleri sunarlar, bu tür programlama araçlarıyla işinizi daha kolay hale getirebilirsiniz.

 

 


 << index              < bölüm 13                 > bölüm 15