課題:講義資料オブジェクト指向プログラムJavaI&IIの中のサンプルプログラ ムについて考察せよ。 *講義資料サンプルプログラム考察については、ローカル変数以降 interface までとする。 <プログラム> class Display { int n; // クラス変数 void Disp() { int i; // ローカル変数 for(i = 1; i <= n; i++) System.out.print(i + " "); } } class VarSample { public static void main(String args[]){ Display obj = new Display(); // クラスDisplayのオ ブジェクトobj生成 obj.n = 10; // オブジェクトobjの 変数に10を代入 obj.Disp(); // オブジェクトobjの Disp()実行 } } <実行結果> 1 2 3 4 5 6 7 8 9 10 <考察> クラス変数 -----> メソッドの外部で宣言した変数。クラス変数はクラス定義          の中で定義され、クラスの特異メソッド、インスタンスメ          ソッド等から参照、代入ができる。 ローカル変数 ---> メソッド内部で宣言した変数。プログラムの中のあるブロッ          ク内で宣言された変数でそのブロック内でのみ有効なもの。          そのブロック内に設けられた新たなブロックの中では有効。 static変数 -----> 関数やブロック内で宣言された変数で、そのブロックが終          了しても値を保持しているもの。静的変数とも言う。 <プログラム> class Sum { int total; Sum() { // コンストラクタ(クラス名と 同名) total = 0; // 0 クリア } void add(int x) { total += x; } } class SumSample { public static void main(String args[]) { Sum obj1 = new Sum(); // クラスsumのオブジェクト obj1生成 Sum obj2 = new Sum(); // クラスsumのオブジェクト obj2生成 obj1.add(10); obj1.add(20); obj2.add(30); obj2.add(40); System.out.println("obj1.total = " + obj1.total); System.out.println("obj2.total = " + obj2.total); } } <結果> obj1.total = 30 obj2.total = 70 *staticを用いたもの* class Sum { static int total; Sum() { // コンストラクタ(クラス名と 同名) total = 0; // 0 クリア } void add(int x) { total += x; } } class SumSample2 { public static void main(String args[]) { Sum obj1 = new Sum(); // クラスsumのオブジェクト obj1生成 Sum obj2 = new Sum(); // クラスsumのオブジェクト obj2生成 obj1.add(10); obj1.add(20); obj2.add(30); obj2.add(40); System.out.println("obj1.total = " + obj1.total); System.out.println("obj2.total = " + obj2.total); } } <結果> obj1.total = 100 obj2.total = 100 <考察> staticなしの時、オブジェクトobj1の変数totalとオブジェクトobj2の変数 totalが異なる。 staticを用いる場合、オブジェクトobj1の変数totalとオブジェクトobj2の変 数totalの値が同じ。 複数オブジェクトを作成してもメモリ領域は等しくなる。 <プログラム> class Sum { int total; Sum() { // コンストラクタ 引数無し total = 0; } Sum(int x) { // コンストラクタ 引数 x total = x; } void add(int x) { total += x; } } class ConstrcSample { public static void main(String args[]) { Sum obj1 = new Sum(); // クラスSumのオブジェクト obj1生成 obj1.add(10); obj1.add(20); System.out.println("sum1 = " + obj1.total); Sum obj2 = new Sum(100); // クラスSumのオブジェクト obj2生成 obj2.add(10); obj2.add(20); System.out.println("sum2 = " + obj2.total); } } <結果> sum1 = 30 sum2 = 130 <考察> コンストラクタ ---> オブジェクト指向言語を作成したプログラムにおいて、 データとそれを操作するための手続きを一体化した『オブジェクト』の生成時 に呼び出される特殊な関数。 <プログラム> class Disp { static { // static イニシャライズ System.out.println("initialize"); } Disp() { // コンストラクタ System.out.println("construct"); } } class StaticSample { public static void main(String args[]) { Disp obj1 = new Disp(); // オブジェクト生成時にコンス トラクタを処理 Disp obj2 = new Disp(); // オブジェクト生成時にコンス トラクタを処理 } } <実行結果> initialize construct construct <考察> staticイニシャライズ・・・プログラムの実行開始後に1回だけ実行される、              特別なコンストラクタ。 static{...}とDisp(){...}の順序を逆にしてもstatic{...}から表示される。 これはクラスが呼ばれたときに自動的に実行され、 コンストラクタよりも早く処理したい場合や、一度だけ処理を行いたい場合 に用いる。 <プログラム> class Display { void Disp() { // メソッド Disp 引数なし System.out.println("Nothing"); } void Disp(int x) { // メソッド Disp 引数 x System.out.println(x); } void Disp(int x, int y) { // メソッド Disp 引数 x, y System.out.println(x + y); } } class OvldSample { public static void main(String args[]) { Display obj = new Display(); // クラスDisplayのオブジェクト obj生成 obj.Disp(); // オブジェクトobjのDisp()を実行 obj.Disp(1); // オブジェクトobjのDisp(1)を実 行 obj.Disp(1, 2); // オブジェクトobjのDisp(1,2)を 実行 } } <実行結果> Nothing 1 3 <考察> obj.Disp()それぞれの()の中の引数の数や型によって実行されるオブジェク トがことなる。 <プログラム> class keisan { static int tanka; private float rate; // private変数rateの宣言 keisan() { // コンストラクタ tanka = 1000; rate = 0.05f; } int keisan(int kazu) { int kingaku; kingaku = (int)(tanka * kazu * (1.0 + rate)); // int型として計 算 return kingaku; } } class PrvSample { public static void main(String args[]) { keisan obj1 = new keisan(); int kazu = 3; int kingaku = obj1.keisan(kazu); System.out.println("tanka = " + obj1.tanka); System.out.println("kazu = " + kazu); System.out.println("kingaku = " + kingaku); System.out.println("rate = " + obj1.rate); // private変数のため 参照不可 } } <実行結果> tanka = 1000 kazu = 3 kingaku = 3150 <考察> public --> 全てのクラスにアクセスを許可する protected --> 同じパッケージ内のコード、または別のパッケージ内のサブクラ スにのみアクセスを許可する private --> 同じクラス内のコードにのみアクセスを許可する <プログラム> class Display { // スーパークラス Display void Disp() { // メソッド System.out.println("Hello!"); } } class Succeed extends Display { // スーパークラス Displayを継承したサ ブクラス Succeed public static void main(String args[]) { // メソッド Succeed obj = new Succeed(); // オブジェクト生成 obj.Disp(); // スーパークラスから 継承したメソッドを利用 } } <実行結果> Hello! <考察> 継承 ---> 既に定義されているクラスをもとに、拡張や変更を加えた新しいク ラスを定義すること。      元になるクラスを「スーパークラス」(super class)、あるいは「基 底クラス」「基本クラス」      (base class)などと呼び、新たに定義されたクラスを「サブクラス」 (subclass)、あるいは「派生クラス」(derived class)と呼ぶ。      スーパークラスの性質はすべてサブクラスに受け継がれ、サブクラ スではスーパークラスとの違いを定義するだけでよい。複数のスー パークラスから新しいクラスを定義することを多重継承という。 <プログラム> class Display { // スーパークラス Display void Disp() { // メソッド System.out.println("Hello!"); } } class Override extends Display { // サブクラス Override void Disp() { // メソッドのオーバー ライド System.out.println("Hello! Java!!"); } public static void main(String args[]) { // メソッド Override obj = new Override(); // オブジェクト生成 obj.Disp(); // メソッド Disp 実行 } } <実行結果> Hello! Java!! <考察> クラスで宣言したメソッドと同じシグネチャを持つメソッドが、そのスーパー クラスで宣言されている場合に、メソッドはオーバーライドされる。 サブクラスのメソッドがスーパークラスのメソッドをオーバーライドすると、 スーパークラスのメソッドは、サブクラスオブジェクトから隠される。 <プログラム> class Display { // スーパークラス Display void Disp() { // メソッド System.out.println("Hello!"); } } class SuperSample extends Display { // サブクラス SuperSample void Disp() { // メソッドのオーバー ライド super.Disp(); // スーパークラスの Disp 実行 System.out.println("Hello! Java!!"); } public static void main(String args[]) { // メソッド SuperSample obj = new SuperSample(); // オブジェクト生成 obj.Disp(); // サブクラスの Disp実 行 } } <実行結果> Hello! Hello! Java!! <考察> super ---> super キーワードは「実行中のインスタンスがインスタンス化さ れたクラスのスーパークラス」を意味する。 スーパークラスの隠蔽された変数や、メソッドにアクセスするために使用する。 <プログラム> class Keisan { // スーパークラス Keisan int x = 100; void add(int x, int y) { // メソッド int w1 = x + y; int w2 = this.x + y; System.out.println("w1 = " + w1 + " w2 = " + w2); } } class ThisSample1 extends Keisan { // サブクラス ThisSample1 public static void main(String args[]) { // メソッド ThisSample1 obj = new ThisSample1(); // オブジェクト生成 obj.add(10, 20); // add 実行 } } <実行結果> w1 = 30 w2 = 120 <考察> w1は、引数から与えられたローカル変数x, yを加算して得た値。 w2の要素はthis.x、つまり当該クラスのメンバ変数xを表している。 よって、w2はメンバ変数xとローカル変数yを加算して得た値。 <プログラム> abstract class PreDefine { // 抽象クラス PreDefine public abstract int add(int x, int y); // 抽象メソッド add public int sub(int x, int y) { // メソッド sub return x - y; } } class AbstractSample extends PreDefine { // 抽象クラス PreDefine の継承 public int add(int x, int y) { // メソッドの内容を具 体的に定義 return x + y; } public static void main(String args[]) { // メソッド AbstractSample obj = new AbstractSample(); System.out.println("add = " + obj.add(100, 80)); System.out.println("sub = " + obj.sub(100, 80)); } } <実行結果> add = 180 sub = 20 <考察> abstractメソッドを含むクラスは、それ自体もabstractで宣言されている必要。 abstractは、クラスに対してインスタンスの作成を禁止する。 abstractクラスは、抽象クラスとも呼ばれ、メンバの宣言のためだけに使う。 (すなわち拡張用のクラス。) <プログラム> interface PreDefine { // インタフェース PreDefine int add(int x, int y); // 抽象メソッド add int sub(int x, int y); // 抽象メソッド sub } class InterfaceSample implements PreDefine { // PreDefine のインプ リメント public int add(int x, int y) { // メソッドの内容を具 体的に定義 return x + y; } public int sub(int x, int y) { // メソッドの内容を具 体的に定義 return x - y; } public static void main(String args[]) { // メソッド InterfaceSample obj = new InterfaceSample(); System.out.println("add = " + obj.add(100, 80)); System.out.println("sub = " + obj.sub(100, 80)); } } <実行結果> add = 180 sub = 20 <考察> interface --> メソッドの本体を定義していないメソッド内だけの集合をイン        ターフェースと言います。厳密には次に示すようにインターフ        ェースを定義します。 [修飾子] interface <インターフェース> [extends<インターフェース名1>, <インターフェース名n>] { [修飾子] 型 変数;   戻り値のデータ型 メソッド名(引数のリスト) } <参考文献> Java言語ハンドブック