前回は,JRubyでSwingを利用するのは速度面で問題があることをお話しました。そこで今回は,第1回で紹介したRubyJavaBridge(rjb)を利用してみましょう。
Windows用のRuby実行環境であるActiveScriptRubyの最新版にはrjbが標準で含まれています。つまり,ActiveScriptRubyをインストールすればrjbがすぐに使えます。rjbを使ってRubyからSwingのウィンドウを表示するプログラムは以下のようになります。
リスト5●rjbSwing.rb require 'rjb' JFrame = Rjb::import('javax.swing.JFrame') JLabel = Rjb::import('javax.swing.JLabel') frame = JFrame.new("Hello World!") label = JLabel.new("Hello World!") frame.getContentPane().add(label) frame.setSize(200,100) frame.setVisible(true) loop do break unless frame.isVisible() sleep(0.1) end
JRubyのプログラムとよく似ていることがおわかりになると思います。違いは,クラスを読み込むメソッドが異なる点,ウィンドウを表示し続けるためのループが最後に必要な点くらいです。もう一つの違いは動作速度です。rjbでは,Swingのウィンドウがすぐに表示されます。ただし,rjbの作者であるarton氏によると,rjbでSwingを利用できるのはWindowsとSolarisだけで,LinuxとMac OS Xでは利用できないそうです。
リフレクション相当の機能を簡単に実現
rjbやJRubyを使うと,Javaの標準のクラスライブラリだけでなく,自作のクラスをRubyから操作することもできます。そこで実験のために以下のようなJavaクラスを用意しました。DogとCatという二つのクラスを用意し,それぞれにbarkとmewという二つのメソッドを実装しています。
リスト6●Animal.java public interface Animal { void bark(); void mew(); } リスト7●Dog.java public class Dog implements Animal { public void bark() { System.out.println("ワン"); } public void mew() { System.out.println("イヌはニャーとは鳴かないよ!"); } } リスト8●Cat.java public class Cat implements Animal { public void bark() { System.out.println("ネコはワンとは鳴かないよ!"); } public void mew() { System.out.println("ニャー"); } }
これらのクラスやメソッドの名前を指定して実行できるようにするにはどうすればいいでしょうか。まず,Javaのプログラムでそのような動作を実現するには,リフレクションという機能を利用します。文字列で指定したクラスを取得する「forName」,インスタンスを生成する「newInstance」,メソッドを実行する「invoke」といったリフレクションで用意されている特殊なメソッドを使うことになります。
一方,rjbで同じ動作を実現するのはあっけないくらい簡単です。第1引数にインスタンス化したいJavaのクラス名,第2引数に実行したいメソッド名を指定して実行するRubyのプログラムは以下のようになります。
リスト9●Pet.rb require 'rjb' Pet = Rjb::import(ARGV.shift) myPet = Pet.new eval("myPet." + ARGV.shift)
たった4行で済んでしまいました。ARGVは,コマンドラインで指定した引数の配列です。shiftは,先頭の引数を返して配列からその引数を削除します。つまり,最初のARGV.shiftは第1引数,次のARGV.shiftは第2引数を表します。evalの中で変数名をハード・コーディングしているのはあまりよくありませんが,たったこれだけでJavaのリフレクション相当の機能を実現できるのです。Javaプログラムを手軽にテストしたい場合などに,rjbはとても重宝しそうです。
ちなみに,JRubyで同様の動作を実現するプログラムは以下のようになります。rjbとはクラスを読み込む方法が若干異なるため,少しだけ面倒です。
リスト10●JRubyPet.rb require 'java' cls = ARGV.shift include_class cls eval("myPet = "+ cls + ".new") eval("myPet." + ARGV.shift)
これで11月のお題「Java関連スクリプト言語」はおしまいです。12月は,Javaプログラミングの情報ページとして有名なJava in the Boxの櫻庭祐一氏に,次期Java SE「Mustang」について解説していただきます。お楽しみに!
【追加のお知らせ】
櫻庭氏による12月のお題は3次元デスクトップの「Project Looking Glass(LG3D)」に変更になりました。もちろん,そのあとの月でMustangについても解説していただきます。LG3D,Mustangともども,改めてお楽しみに!