Day: February 14, 2007

JFreeChartで生成したグラフをServletで出してみる(JFreechart 0.9.16)

グラフをただ出すだけなら,JFreeChartとServletそれぞれに関して若干の知識があればどうってことなくできる気がするが,確認のためにグラフをただ出してみた.サンプルその他の注意点 サンプル 本頁のサンプルは本当にグラフをただ出すだけである.JFreeChartオブジェクトは以前作成した棒グラフを出力するサンプルを流用する. その他の注意点

JavaでSAX

JavaでSAXクラスライブラリを使用したプログラミングをしてみた.SAXとは環境の準備早速試す SAXとは SAXはSimple API for XMLの略である.その名のとおり(?),XMLプログラミングの際に嬉しいAPIである.JavaではSunがJAXP(Java API for XML Programing)というパッケージにSAXに対応したXMLパーサが入っている(このパッケージには,DOMに対応したXMLパーサも入っている).SAXではXML文書を読み込んで,XML文書の先頭があった,タグがあった,文字列があった,などというイベントを検出し,イベントごとに設けられたメソッドを実行していくものである.文書を局所的にみて処理を行うので,パースにかかるメモリはDOMに比べて少なくて済む.その代わり,文書の局所しか見れないので,全体を見舞わした処理や前の要素に戻るという処理には向かない. 環境の準備 SAXのクラスライブラリを使うために.apt-get install libxerces-javaexport CLASSPATH=/usr/share/java/xerces.jarこれでjavax.xml.parsersをimportできる.ドキュメントによるとDOMのページで書いたlibcrimson-javaでもSAXができそうな雰囲気を感じた.apt-cache showによると,xercesはXMLスキーマ,DOM,SAXをサポートしているらしい. 早速試す

JavaでDOM

JavaでDOMクラスライブラリを使用してプログラミングしてみる.DOMとSAXDOMとは環境の準備DOMでXML文書を読む DOMとSAX XMLパーサとして,DOMとSAXがある.これらは,XML文書をプログラムで扱う際の方式である.それぞれに対応したXMLパーサ(ライブラリ)が多くの言語で提供されている.DOMとSAXはどう違うのかは,本ページの「DOMとは」とJavaでSAXのページの「SAXとは」を参照. DOMとは DOMはData Object Modelの略である.JavaではSunがJAXP(Java API for XML Programing)というパッケージにDOMに対応したXMLパーサが入っている(このパッケージには,SAXに対応したXMLパーサも入っている).DOMでは,XML文書を一気に読み込んで,要素のツリーを構築する.このツリーをランダムに行き来したり,削除したりすることができる.その代わり,要素のツリーを構築するために大きなXML文書を読み込むにはそれなりのメモリを必要とする.イメージとしてはDOMはXMLを大局的にとらえるのに向き,SAXは局所的にとらえるのに向く,と思う. 環境の準備 DOMのクラスライブラリを使うために.apt-get install libcrimson-java libcrimson-java-docexport CLASSPATH=/usr/share/java/xerces.jarこれでorg.apache.crimsonをimportできる.このパッケージやSAXのページで述べるパッケージのクラスのようにXML文書を扱うことのできるモジュールをXMLパーサと呼ぶ.apt-cache showによると,libcrimson-javaはJAXPをサポートしているらしい. DOMでXML文書を読む DOMでXML文書を読み込むと,ツリーが出来上がる.ツリーのノードとなるのは,タグやテキストなどである.DOMを使用すると,これらのノードを取得したり,子ノードに移動したりできる.もちろん要素の名前やノードの種類やノードの値などを取得できる.DOMを使用したサンプルプログラムを以下に示す.

メソッドを呼び出す

ネイティブコードからクラスやオブジェクトのメソッドを呼び出す.流れサンプルインスタンスメソッドとスタティックメソッドメソッドIDの取得とシグネチャjavap 流れ メソッドを呼び出す時の流れは,フィールドの取得や設定とそんなに変わらない.以下にその流れを示す. インスタンスメソッドの場合 スタティックメソッドの場合 必要があればGetObjectClassでjclassを取得する GetMethodIDでメソッドIDを取得 GetStaticMethodIDでメソッドIDを取得 Call<Type>Methodでメソッドを呼び出す CallStatic<Type>Methodでメソッドを呼び出す <Type>にはメソッドの返り値の型と対応するInt,Short,Byteなどが入る. サンプル 流れが掴めたところでサンプルを示す.まずはネイティブコードから呼び出されるメソッドを保持するクラス. ここにはスタティックメソッドとインスタンスメソッド,そしていろんなアクセス修飾子を混ぜてみた.次にこのクラスのメソッドをネイティブコードを介して呼び出すクラス. そしてネイティブメソッド.まずヘッダ. そして本体. 以下実行結果.publicVoidMethod()pkgPrivateIntMethod()return 1protectedCharMethod(hoge)return hprivateDoubleMethod(1.0)return 1.0フィールドの場合と同様,privateなメソッドを呼び出したりもできる. … More メソッドを呼び出す

参照

参照とポインタは同じ概念のはずだが,JNIでは明確に区別する必要がある.JavaにはポインタがないJNIで何を考慮すべきかローカル参照グローバル参照参照についてのまとめ Javaにはポインタがない 「JavaにはポインタがないからCより簡単だ」これはJavaの入門書などでよくみかける.確かにJavaにはポインタと呼ばれるものはないが,参照があるので同じことだ.まともなプログラミング言語ならポインタに相当するものは大抵あるものだ.ないとなるとその言語の表現力に大きく影響してしまう.で,Cにおけるポインタとは何か.「オブジェクトを指し示すもの」である.多くの場合それはアドレスで実装されるが,別にC言語の仕様ではない(ハズ)が,ここではアドレスで実装するものと考える.Javaにおける参照とは何か.これもやはり「オブジェクトを指し示すもの」である.実装についての仕様はよくわからないが,以下を踏まえておく必要がある.JVMはGCでオブジェクトを削除する.JVMはGCでオブジェクトを再配置する.オブジェクトのアドレスがJVMによって動的に変化するから,参照は直接,または短絡的にアドレスで実装しいるわけではないと思う.オブジェクトへの参照と実際のアドレスはJVMによって管理される.ポインタと参照にはこのような違いがあるが,ポインタと参照は同じ「オブジェクトを指し示すもの」であるので,プログラマから見ればC,Javaそれぞれ単独でコーディングする上では両者の違いはほとんどない(「ポインタ演算」相当の「参照演算」なんてものはないが).が,JNIで両者が出会うとき,ポインタと参照の違いは明確に意識しておく必要がある. JNIで何を考慮すべきか ポインタと参照の違いは簡単に言うと,「プログラマが責任をもって管理するか,JVMがいろいろと操作をするか」である.そしてこの違いはCとJavaが出会うJNIのネイティブコードでは特に意識する必要がある.ネイティブコードはCもしくはC++である.いうまでもなく,ポインタは従来どおりのポインタとして扱える.問題は参照である.概念的にはポインタと参照は同じだが,参照はJVMにより管理,操作される.したがって,たとえ参照がポインタと同じように見えてもプログラマが好き勝手に保持,操作してはいけない. ローカル参照 JVMはネイティブコードに渡した参照に関する情報をテーブルに保持する.これにより,JVMは「ネイティブコードでこの参照が使用されているからGCのときに注意しなければならない(削除や移動をしてはいけない)」ことがわかる.このテーブルに保持される参照にはネイティブメソッドの引数にある全ての参照と返り値のための参照が含まれる.このテーブルに含まれる参照はローカル参照と呼ばれる.ローカル参照はそのネイティブメソッドの呼び出しの間でだけ有効である.すなわちネイティブコードのグローバル変数で参照を保持しておいて,複数のネイティブメソッドで使用することはできない.ネイティブメソッドの呼び出しが異なれば,テーブルに保持されている参照は無効になる.したがって,別のネイティブメソッドでその参照を使用すると結果は保証されない.やってはいけない例を以下に示す.まず不正なネイティブメソッドを呼び出すJavaクラス. 上のクラスファイルから生成されるヘッダ. そして不正なネイティブコード. 上のネイティブコードでは,methodAでオブジェクトへの参照である引数objをグローバル変数invalidLocalReferenceに格納してmethodBでそれを使用している.これを実行すると私の環境では以下のようになった. なんかアボートした.黙ってそのまま実行されるよりはましだ. グローバル参照 先のサンプルは,ネイティブコードにおいてローカル参照をグローバル変数に格納する間違った例であった.しかし,JNIでは参照をネイティブコードでグローバル変数に格納する手段を提供されている.このとき,その参照はグローバル参照と呼ばれる.具体的な方法は,JVMにあるローカル参照をネイティブコードにおいてグローバルに参照する(グローバル参照とする)ことを伝えるものである.それはJNIEnvの関数であり,jni.hでは以下のように定義されている.jobject (JNICALL *NewGlobalRef)(JNIEnv *env, jobject lobj);引数にlobjとあるのはローカル参照ということだろう.そして返り値をグローバル参照としてグローバル変数に格納すればよい.この関数を使用して先の間違ったサンプルを修正してみた.まず,グローバル参照を使用するネイティブコードを呼び出すJavaコード. そして上のJavaコードから生成されるヘッダ. そしてグローバル参照を使用するネイティブコード.