通常、

static String data;

のように宣言したものは1つのインスタンスしかない。

このため、たいていは1つのアプリケーション内でstaitcとした場合に、
そのオブジェクトは共有している1つのオブジェクトと見なすことが出来る。

ただし、通常と記述したのは、そうでないかもしれないからである。
それが今回の話です。

package loader.data;

public class Sample implements ISample {
	
	private static String data = "ABC";
	
	@Override
	public String getData() {
		return this.data;
	}

	@Override
	public void setData(String data) {
		this.data = data;
	}
}

のようなクラス定義する。
このstaticのdataインスタンスを同時に2つ保持してみる。

話が逆になってしまうが、インターフェースも作っている。
この理由は後で述べる。

package loader.data;
public interface ISample {
	public String getData();
	public void setData(String data);
}

こんな、インターフェースの定義になっております。

さて、ここから、サンプルです。

public static void test0() throws Exception{
	log.info("========== test 0 ============");
	
	ISample obj1 = new Sample();
	ISample obj2 = new Sample();
	
	obj1.setData("OBJ-1");
	obj2.setData("OBJ-2");
	
	log.info("obj1 => " + obj1.getData());
	log.info("obj2 => " + obj2.getData());
}

こんな処理を流してみます。
当然、こうなります。

ClassLoaderSample.java - ========== test 0 ============
ClassLoaderSample.java - obj1 => OBJ-2
ClassLoaderSample.java - obj2 => OBJ-2

“OBJ-1″と”OBJ-2″のデータを同時に保持したかったのですが、
それは出来ません。

では、

public static void test1() throws Exception{
	
	log.info("========== test 1 ============");
	
	ClassLoader loader1 = new SampleClassLoader();
	ClassLoader loader2 = new SampleClassLoader();
	
	Class cls1 = loader1.loadClass("loader.data.Sample");
	Class cls2 = loader2.loadClass("loader.data.Sample");
	
	ISample obj1 = (ISample)cls1.newInstance();
	ISample obj2 = (ISample)cls2.newInstance();
	
	obj1.setData("OBJ-1");
	obj2.setData("OBJ-2");
	
	log.info("obj1 => " + obj1.getData());
	log.info("obj2 => " + obj2.getData());

}

これを実行すると

ClassLoaderSample.java - ========== test 1 ============
SampleClassLoader.java - findClass(loader.data.Sample)
SampleClassLoader.java - findClass(loader.data.Sample)
ClassLoaderSample.java - obj1 => OBJ-1
ClassLoaderSample.java - obj2 => OBJ-2

できました。別の文字列を保持しています。

ここで、SampleClassLoaderは私が作成したクラスローダーです。
この中身は後日説明します。
まずは、クラスローダーのインスタンスが異なる。ということです。
TomcatなどではWEBアプリごとに別のバージョンのライブラリが使えます。
つまり、WEBアプリ毎にstaticオブジェクトが存在する訳です。
(じゃないと、他のアプリから値が書き換えられてしまいます・・・それはあり得ないですよね・・・)

これをJavaVM上で実現しているのがClassLoaderという訳です。
つまり、ClassLoader毎に同じクラスファイルを使って、別のクラス(Class)として扱うことが出来るわけです。
この仕組みを使えば、staticのdataオブジェクトが複数持てるという事です。

最後に、ISampleというように別途インターフェースを用意したのは、
同じクラスのように見えますが、別のクラスローダーで読みこんだクラスは別のクラスです。
従って、同様に操作するためにもインターフェースの定義がないと、メソッドの実行もリフレクションを使ってすることになってしまいますので、
それでは面倒なので、インターフェースを通して処理をしています。

ちなみに、普通にクラスローダーを作ると、
当然ISampleのインターフェースも別のものですから、普通に実行すると、

Exception in thread "main" java.lang.ClassCastException: loader.data.Sample cannot be cast to loader.data.ISample

のようなエラーが発生してしまいます。

これを抑制するために、クラスローダー内でインターフェース定義は共通のクラスローダーから読むようにしているのですが、
そのあたりは、クラスローダーの説明で記述します。

なんで、こんな事をしようと思ったかと言えば、

前回のWebSocketのフレームワークを作っているときに、
何とか、WebSocketでの接続セッションで共有のオブジェクトが必要な時に、フレームワークが上位からコンテナを用意してあげるかと考えましたが、
Singletonクラスなどで共有するのもありだなと思ったのがきっかけです。

あとは、自動的なリローダブルな構造を実現する。
要は、実行中にプログラムを書き換え可能にするための仕組みです。

ClassLoaderを自作するのは通常は禁じ手でしょうが、
フレームワークまで考えると、理解しておく必要がある重要なJavaの要素と言えると思います。

お仕事のご依頼・相談を承ります
この記事に関連するお仕事のご依頼やご相談をお待ちしております。 詳しくは、こちら

Leave a Reply

お仕事のご依頼・相談
この記事に関連するお仕事のご依頼やご相談をお待ちしております。 詳しくは、こちら
ソフトウェア&ライブラリ




ライブラリ
airxmail(en)
AIR版メール送受信ライブラリ
airxzip
AIR版ZIP圧縮・解凍ライブラリ
執筆書籍
本、雑誌等

WEB記事:CodeZine
執筆記事はこちら
カレンダー
2013年1月
« 12月   2月 »
 123456
78910111213
14151617181920
21222324252627
28293031  

カスタム検索
RSS
Add to Google < !–adsense–>
アーカイブ
カテゴリ
にほんブログ村 IT技術ブログへ