なぜか、シリーズ化してしまった、依存性の問題の対応策、前回は、汎用性を高めるため、引数だけ、共通化するという方法を書きました。
具体的には、
1.引数をハッシュマップなどにいれ、そのハッシュマップを引数にする
か、Strutsなどで利用されている
2.引数を「ある型」から継承したものにして、メソッドの引数には、「ある型」を書く
ということについてあげました。
今回は、1において、コンパイルでは、引数は共通だから通るんだけど、実行時には、落ちて分かるようにする方法を書きます。実は、この方法、2では、同じ仕組みでわかるようになってます。
では、それについて書きます。
■「引数は共通」だけど、実行時に落ちる方法(変更前)
いままでの例である、エラーメッセージを出すという話です。
今回は、引数をまず、argというクラスの中に入れ、そのargを、ハッシュマップにセットします。
argの内容は、以下のとおり
public class arg { public String msg = null; } |
そーなると、a(呼び出し側)は、こんなかんじ
import java.util.*; public class a { /* * メイン処理 * @param args 外部から渡される引数 */ public static void main(String[] args) { HashMap map = new HashMap(); arg hikisu = new arg(); hikisu.msg = "aのメッセージ"; map.put("arg",hikisu); b.errmsg(map); } } |
呼ばれて、エラーメッセージを出すbは、こんなかんじ
import java.util.*; public class b { /** * エラーメッセージ出力 * @param map 引数が入ったハッシュマップ */ public static void errmsg(HashMap map) { arg hikisu = null; try { hikisu = (arg)map.get("arg"); if ( hikisu == null ) { System.out.println("引数がない"); throw new RuntimeException(); } } catch(Exception e) { System.out.println("引数が古い"); throw new RuntimeException(); } // 出力 System.out.println(hikisu.msg); } } |
もう一方の呼ばれる側d(呼び出し側)は、こんなかんじ
import java.util.*; public class d { /* * コンストラクタ */ public d() { HashMap map = new HashMap(); arg hikisu = new arg(); hikisu.msg = "作成"; map.put("arg",hikisu); b.errmsg(map); } } |
■「引数は共通」だけど、実行時に落ちる方法(仕様変更の結果)
ここで、レベルを入れるということに変更します。
ただし、aとbだけに連絡が行っているとします。
今度新しい引数をarg1とすると、その内容は、以下のとおり
public class arg1 { public String msg = null; public int level = 0; } |
このとき、aは、以下のとおり
import java.util.*; public class a { /* * メイン処理 * @param args 外部から渡される引数 */ public static void main(String[] args) { HashMap map = new HashMap(); arg1 hikisu = new arg1(); hikisu.msg = "aのメッセージ"; hikisu.level = 10; map.put("arg",hikisu); b.errmsg(map); } } |
(赤字は仕様変更で修正したところ)
そして、bは、以下のとおり
import java.util.*; public class b { /** * エラーレベル */ public static int errlevel = 0; /** * エラーメッセージ出力 * @param map 引数が入ったハッシュマップ */ public static void errmsg(HashMap map) { arg1 hikisu = null; try { hikisu = (arg1)map.get("arg"); if ( hikisu == null ) { System.out.println("引数がない"); throw new RuntimeException(); } } catch(Exception e) { System.out.println("引数が古い"); throw new RuntimeException(); } // 出力 if ( hikisu.level >= errlevel) { System.out.println(hikisu.msg); } } } |
(赤字は仕様変更で修正したところ。> は、実際には半角)
つまり、引数を受け取るときにキャストし、古い型だったら、ランタイム例外で落とします。
で、dは修正していませんが、問題なくリンクできます。
そして、dがどこからか呼ばれて、表示しようとすると、
”引数が古い”とでて、ランタイムエラーになるのでわかります。
これは、引数をキャストするとき、型が違うため、エラーになるということを利用しています。
おなじような現象として、Strutsなどで、実際に引数を利用するときは、引数をキャストして使うので、ここで、古い型のものでかいてあれば、エラーになります。
ということで、
・今回の例のように、なにかを包んで、中身から出すときにキャストして、
古かったらエラーにするもの(ある意味委譲のやり方に似ている)や、
・Strutsのような、継承の型で、親の型を引数とし、実際に利用するときキャストして
古かったらエラーにするものがあるのですが、
この継承でやる方法と、委譲でやる方法、意味があって、使い分けます。
それについては、次回のこのシリーズに書きます。