Report#5(Java)

 講義資料オブジェクト指向プログラムJavaI&IIの中のサンプルプログ ラムについて考察せよ。

● 講義資料サンプルプログラム考察については、ローカル変数以降 interfaceまでとする。

ローカル変数とクラス変数

クラス変数・・・メソッドの外部で宣言した変数。クラス変数はクラス定義の中で定義され、        クラスの特異メソッド、インスタンスメソッドなどから参照/代入ができる。 ローカル変数・・・メソッド内部で宣言した変数。プログラムの中のあるブロック内で宣言された変数で、        そのブロック内でのみ有効なもの。局所変数ともいう。        そのブロック内に設けられた新たなブロックの中では有効である。

  class Demo {      //クラスDemo
    int a;        //クラス変数 a
    void Demo1() {    //メソッドDemo1
      int x;       //ローカル変数 x
      …
    }
    vod Demo2() {     //メソッドDemo2
      int x;       //Demo2のローカル変数 x
      …
}
  } 

【ローカル変数の例プログラム】
void  funcA()    //  関数 A
{
  int    x;            // x は数値(int)とする
  char*  s = "abc";    // s は文字列(char*)とする

  x = strlen( s );    // そして本文である処理内容を書く
}


void  funcB()    //  関数 B
{
  int  x, y;    // x, y は数値(int)とする
                 // ただし、x は、上記 funcA の x とは別の変数である
  x = 4;
  funcA();          // funcA を実行しても、x は 4 が保持される
  y = 2 * x + 5;    // y = 13
}

上記のように関数の中で宣言すれば、 関数の中だけ有効になるので、 別の関数の中で宣言された変数とは 別の記憶領域がつかわれている。 このように、関数の中だけで有効になる変数を ローカル変数と呼ぶ。

【1からnまでを表示するプログラム例 】
class Display {
    int n;                                      // クラス変数 n
        void Disp() {
        int i;                                   // ローカル変数 i
        for (i = 1; i <= n; i++){                // i を 1 から n までループする。
            System.out.print(i + " ");           
        }
        }
}

    class VarSample {
        public static void main(String args[]) {
            Display obj = new Display();             // クラスDisplayのオブジェクトobjを生成する。
            obj.n = 10;                              // オブジェクトobjの変数nに10を代入する。
            obj.Disp();                              // オブジェクトobjのDisp()を実行。
        }
    }

【実行結果】
[nw0364:~/Sites/Java/Repo_5] j03064% javac VarSample.java
[nw0364:~/sites/java/Repo_5] j03064% java VarSample
1 2 3 4 5 6 7 8 9 10

static変数

static変数・・・関数やブロック内で宣言された変数で、そのブロックが終了しても値を保持しているもの。          静的変数とも言う。          生成されたオブジェクトの個数や状態をそのブロック内に格納しておく変数として使う。          グローバル変数のように、他の関数から使用することはできない。

【異なるオブジェクト間の変数合計プログラム例 】
 
  class Sum {
    int total;
    Sum() {                              // コンストラクタ(クラス名と同名)
      total = 0;                         // 0を クリアする。
    }
    void add(int x) {
      total += x;                        //totalの値が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でxに10を代入。
      obj1.add(20);                      // obj1でxに20を代入。
      obj2.add(30);                      // obj2でxに30を代入。
      obj2.add(40);                      // obj2でxに40を代入。
      System.out.println("obj1.total = " + obj1.total);
      System.out.println("obj2.total = " + obj2.total);
    }
  } 

【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac SumSample.java
[nw0364:~/sites/java/Repo_5] j03064% java SumSample
obj1.total = 30
obj2.total = 70

*オブジェクトobj1の変数totalとオブジェクトobj2の変数totalが異なる。 *メモリ容量が異なるから。 ○次はstatic変数を用いたプログラム。↓↓↓↓

【staticを用いて値を共有するプログラム例 】
 
class Sum {
    static int total;                    // クラス変数staticを宣言し、値を共有させる。
    Sum() {                              // コンストラクタ(クラスSum)。
        total = 0;                         // totalを0に初期化する。
    }
    void add(int x) {
        total += x;                     //引数xの値をtotalに加える。
    }
}

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()メソッドに引数を入力し、呼び出す。
        obj1.add(20);                     //             〃
        obj2.add(30);                     // obj2のadd()メソッドに引数を入力し、呼び出す。
        obj2.add(40);                     //             〃
        System.out.println("obj1.total = " + obj1.total);
        System.out.println("obj2.total = " + obj2.total);
    }
}

【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac SumSample2.java
[nw0364:~/sites/java/Repo_5] j03064% java SumSample2
obj1.total = 100
obj2.total = 100

*オブジェクトobj1の変数totalとオブジェクトobj2の変数totalの値が同じ。 *値を共有している。 *複数オブジェクトを生成してもメモリ領域は等しくなる。 *スタティック変数は、関数のトップブロックの最初に、static属性を用いて宣言され、静的空間に領域 が確保される。(関数が呼ばれた時点で以前の値を保持している。) *スタティック変数への初期化0 (ゼロ)は、main()が呼び出される前に一度だけ行われる。

コンストラクタ

コンストラクタ・・・オブジェクト指向言語で作成したプログラムにおいて、データとそれを操作するため          の手続きを一体化した「オブジェクト」の生成時に呼び出される特殊な関数。           オブジェクトが扱うデータの初期化などをここで行なう。

【コンストラクタを用いた合計プログラム例】
 
class Sum {
    int total;                           //インスタンス変数totalを宣言。
    Sum() {                              //totalの値を0に初期化するコンストラクタ。
        total = 0;
    }
    Sum(int x) {                         //totalの値に初期化するコンストラクタ。
        total = x;
    }
    void add(int x) {                    //引数の値をtotalに加えるメソッド。
        total += x;
    }
}

class ConstrcSample {
    public static void main(String args[]) {
        Sum obj1 = new Sum();              // クラスSumのオブジェクトobj1を生成。(*1)
        obj1.add(10);                      // obj1のadd()メソッドを、引数を入力して呼び出す。
        obj1.add(20);                      //                〃
        System.out.println("sum1 = " + obj1.total);
        Sum obj2 = new Sum(100);           // クラスSumのオブジェクトobj2を生成。(*2)
        obj2.add(10);                      // obj2のadd()メソッドを、引数を入力して呼び出す。
        obj2.add(20);                      //                〃
        System.out.println("sum2 = " + obj2.total);
    }
}

【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac ConstrcSample.java
[nw0364:~/sites/java/Repo_5] j03064% java ConstrcSample
sum1 = 30
sum2 = 130

*1:obj1.totalは0に初期化、その後obj1.add()によってobj1.total = 30;となる。 *2:obj2.totalは引数の値(100)に初期化、その後obj2.add()によってobj2.total = 130;となる。

staticイニシャライズ

staticイニシャライズ・・・プログラムの実行開始後に1回だけ実行される、特別なコンストラクタ。 ●staticイニシャライズは、クラスが呼ばれた(ロードされた)ときに自動的に実行される。 ●コンストラクタよりも早く処理したい場合や、一度だけ処理を行いたい場合などに用いる。

【staticイニシャライズを行ったプログラム例 】
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();            // オブジェクト生成時にコンストラクタを処理(*1)
        Disp obj2 = new Disp();            // オブジェクト生成時にコンストラクタを処理(*2)
    }
}

【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac StaticSample.java
[nw0364:~/sites/java/Repo_5] j03064% java StaticSample
initialize
construct
construct

(*1)・・・コンストラクタをロードするより先にstaticイニシャライザが実 行される。よって、

initialize construct が表示される。 (*2)・・・すでにobj1で実行したので、そのままコンストラクタのロードに入る。よって、

construct が表示される。

メソッドのオーバーロード

メソッドのオーバーロード・・・同じメソッド名で、引数リストの異なるメソッドを同時に定義することを、               メソッドのオーバーロードと呼ぶ。                メソッドのオーバーロードは、メソッドの意図を明確に保ちながら、様々 なパラメータを渡してメソッドから受け取る値に影響を与えるための手段と               して優れている。                メソッドを識別するのに、メソッド名と引数リストの組を使う。これをシグ               ネチャ(署名)と呼び、同じメソッド名でも、引数リストの異なるものは、別               のものとして扱われる。

■メソッドをオーバーロードする理由
          メソッドをオーバーロードすることによって、インターフェイスに一貫性を持たせ、どのデータ型を渡す 場合でも、論理的に整合性のある形でメソッドを呼び出すことができる。新しい名前や名前規約を考え出す よりも、同じ名前を使用した方が、プロージャがどのような機能を持っているのかを思い出しやすくなる。

【メソッドのオーバーロードを行ったプログラム例】
class Display {
    void Disp() {                          // メソッド Disp 引数なし。
        System.out.println("Nothing.");
    }
    void Disp(int x) {                     // メソッド Disp int型の引数 x を宣言。
        System.out.println(x);
    }
    void Disp(int x, int y) {              // メソッド Disp int型の引数 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)を実行。引数が1個。
        obj.Disp(1, 3);                 // オブジェクトobjのDisp(1,2)を実行。引数が2個。
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac OvldSample.java
[nw0364:~/sites/java/Repo_5] j03064% java OvldSample
Nothing.
1
4
*メソッドのオーバーロードを行う場合は、引数の数や型が異なっていなければない。

アクセス制御

アクセス修飾子 public クラス、インターフェイス、メソッド、変数、コンストラクタの宣言で使用できる。 パッケージ間を問わずに、あらゆるアクセスの許可を表す。 publicクラスは、必ずファイル名と同じである必要がある。 そうでない場合は、コンパイルエラーが発生する。 protected メソッド、コンストラクタ、変数の宣言で使用する。 ただし、静的変数の宣言には使えない。 同一クラス、同一パッケージ、サブクラスからのアクセスを許可する。 private メソッド、コンストラクタ、変数の宣言で使用する。 ただし、静的変数の宣言には使えない。 同一クラス内からのアクセスのみ許可し、データを隠蔽する。 他のクラスからのアクセスは、たとえ同一クラス内からでも拒否される。 import 現在記述しているファイルで、短い名前でクラスを参照できるようになる。 import文はひとつのファイルで複数指定できる。 必ずファイルの先頭に記述する。ただしpackageステートメントがある場合はその後で。

【privateを用いて変数の参照を不可にするプログラム例】
class keisan{
    static int tanka;                     //int型のクラス変数tankaを宣言する。
    private float rate;                   //修飾子private変数の、float型rateを宣言する。
    keisan(){                             //コンストラクタ
        tanka = 1000;                     //tankaを1000に初期化。
        rate  = 0.05f;                    //rateを0.05fに初期化。
    }
    int keisan(int kazu){
        int kingaku;
        kingaku = (int)(tanka * kazu * (1.0 + rate));
        return kingaku;
    }
}

class PrivateSample{
    public static void main(String args[]){
        keisan obj = new keisan();         //クラスkeisanのオブジェクトを生成。
        int kazu = 3;
        int kingaku = obj.keisan(kazu);    //obj.keisanメソッドを引数にkazu=3を入力して呼び出す。
                                           //その値をkingakuに代入する。
        System.out.println("tanka   = " + obj.tanka);
        System.out.println("kazu    = " + kazu);
        System.out.println("kingaku = " + kingaku);
        //System.out.println("rate    = " + obj.rate);  //private変数のため参照不可!・・・(*1)
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac PrivateSample.java
[nw0364:~/sites/java/Repo_5] j03064% java PrivateSample
tanka   = 1000
kazu    = 3
kingaku = 3150
(*1)・・・private変数のため、クラス外からの呼び出しは拒否されてしまう。

継承

継承・・・既に定義されているクラスをもとに、拡張や変更を加えた新しいクラスを定義すること。     元になるクラスを「スーパークラス」(super class)、あるいは「基底クラス」「基本クラス」     (base class)などと呼び、新たに定義されたクラスを「サブクラス」(subclass)、あるいは     「派生クラス」(derived class)と呼ぶ。      スーパークラスの性質はすべてサブクラスに受け継がれ、サブクラスではスーパークラスとの違     いを定義するだけでよい。複数のスーパークラスから新しいクラスを定義することを多重継承とい     う。

■基本書式

class クラス名 extends スーパークラス {
内容
}
*既存のクラスから派生したクラスを作成したい場合、クラス定義時にextends キーワードを記述する。

【継承の動きを表すプログラム】
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();                             // スーパークラスから継承したメソッドを利用。
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac Succeed.java
[nw0364:~/sites/java/Repo_5] j03064% java Succeed
Hello!
*サブクラスの中でスーパークラスの変数やメソッドが継承され、利用可能となる。

【オーバーライドのプログラム】
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 実行
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac OverRide.java
[nw0364:~/sites/java/Repo_5] j03064% java OverRide
Hello! Java!!
*オーバーライドは「上書き」のこと。継承時に、スーパークラスで定義されたメソッドと同じ名前、  引数を持つメソッドを、サブクラスでもう一度定義すること。 *オーバーライドした場合は、後で定義したほうを優先する。

■継承の特徴

・継承は一つのクラスからしか出来ない。(スーパークラスは一つしかもてない。) ・サブクラスは幾つでも作れる。 ・継承の階層は問わない。何階層でも継承される。 ・メンバ変数、メソッドは継承される。 ・インスタンス化したクラスは、スーパークラスから継承した機能しか利用できない。 ・コンストラクタは継承されない。そのクラス固有のもの。 ・継承時にメンバ変数名、メソッド名が重なったら、インスタンス化されたクラスから最も階層が近いスー パークラスの定義が採用される。つまり、継承時に既存のメンバ変数、メソッドを変更することが出来る。

super

super super キーワードは「実行中のインスタンスがインスタンス化されたクラスのスーパークラス」を意味する。 スーパークラスの隠蔽された変数や、メソッドにアクセスするために使用する。

【superキーワードを使ったプログラム】
class Display {                                 // スーパークラス
Display
    void Disp() {                               // メソッド
        System.out.println("Hello!");
    }
}

class SuperSample extends Display {             // 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実行。
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac SuperSample.java
[nw0364:~/sites/java/Repo_5] j03064% java SuperSample
Hello!
Hello! Java!!

this

thisキーワード ●this はカレントクラスを参照するときに利用する。 ●例えば、クラス変数と同クラス内のメソッド変数が同じ名前であるとき、クラス変数は this. を付けて使い分けることが可能となる。 ●thisキーワードを使用することによって、インスタンスメソッドのメンバ変数をより明確に表現できる。 ※this.name は、「このオブジェクトのメンバー変数 name」 と言う意味。

【thisキーワードを使用したプログラム1】
class Keisan {                                 // スーパークラスKeisan
    int x = 100;                               // メンバ変数xを100に設定。
    void add(int x, int y) {                   // メソッド
        int w1 = x + y;                        // 引数 x、y 同士を足してw1に代入。
        int w2 = this.x + y;       //メンバ変数xと、ローカル変数yを足してx2に代入。
        System.out.println("w1 = " + w1 + "  w2 = " + w2);
    }
}

class ThisSample1{                              // サブクラスThisSample1
    public static void main(String args[]) {    // メソッド
        Keisan obj = new Keisan();    // オブジェクト生成
        obj.add(10, 20);                        // add 実行
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac
ThisSample1.java                     
[nw0364:~/sites/java/Repo_5] j03064% java ThisSample1
w1 = 30  w2 = 120
*w1は、引数から与えられたローカル変数x, yを加算して得た値。 *w2の要素はthis.x、つまり当該クラスのメンバ変数xを表している。 *よって、w2はメンバ変数xとローカル変数yを加算して得た値。

【thisキーワードを使用したプログラム2】
      class Keisan{
      Keisan(int x, int y){             //引数が2つのコンストラクタ
         System.out.println("Keisan = " + (x * y));
     }
     Keisan(int x){                     //引数が1つのコンストラクタ
         this(x, 1);                    //Keisan(x、y)と同じ。
     }
 }
 
 class thisSample2{                          //サブクラス ThisSample2
     public static void main(String args[]){ //メソッド
         Keisan2 obj1 = new Keisan2(200, 5); //引数が2つのコンストラクタ実行
         Keisan2 obj2 = new Keisan2(200);//引数が2つのコンストラクタ実行
     }
 }


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac ThisSample2.java                 
[nw0364:~/sites/java/Repo_5] j03064% java ThisSample2
Keisan = 1000
Keisan = 200

abstract

abstract

●bstract 宣言された抽象メソッドをもつクラスは、abstract を付けて抽象クラスにする。 ●抽象クラス内の抽象メソッドは戻り値と引数のみを定義する。 ●より確実にオーバーライドを利用するクラスを生成するにはabstract修飾子を利用する。 ●bstractクラスは、「class」の前に「abstract」をつけないと、コンパイルエラーになってしまう。

■基本書式

abstract class クラス名 {
member...          //member...には、クラスのメンバを記述
}
abstractは、クラスに対してインスタンスの作成を禁止する。 abstractクラスは、抽象クラスとも呼ばれ、メンバの宣言のためだけに使う。 (すなわち拡張用のクラス。)

【abstractを使用したプログラムj】
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();// クラスAbstractSampleのオブジェクトobjを生成
        System.out.println("add = " + obj.add(100, 80));
        System.out.println("sub = " + obj.sub(100, 80));
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac AbstractSample.java
[nw0364:~/sites/java/Repo_5] j03064% java AbstractSample
add = 180
sub = 20
*抽象メソッドを使用する場合、サブクラスでこのメソッドをオーバーライドして中身を定義する。

interface

interface ●内容に抽象メソッドしか持たないクラスのようなものをインタフェースと呼ぶ。 ●クラスと並んで、パッケージのメンバーとして存在する。 ●インタフェースはクラスによって実装 (implements) され、実装クラスはインタフェースで宣言 されている抽象メソッドを実装する。

■インタフェイスの基本書式

[修飾子] interface <インタフェース名> {
    データ型 変数名=値;
    修飾子 戻り値のデータ型 メソッド名(引数の型宣言);
}
※interface の修飾子は public のみ。 ※メンバ変数は、必ず値が代入されなければない。 ●インタフェースは、定数と抽象メソッドだけ、内容に持つことが出来ます。オブジェクトのインタフェース になるメソッドを宣言するためのものなので、妥当だといえます。データをどの用に保持するのか、処理の手 続きはどうするのかといったことは、利用する側のオブジェクトには関係ないからです。必要なのは、メソッ ド名、引数、戻り値の型だけです。インタフェースでは、これを宣言します。

【interfaceを使用したプログラム】
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));
    }
}


【実行結果】
[nw0364:~/sites/java/Repo_5] j03064% javac InterfaceSample.java
[nw0364:~/sites/java/Repo_5] j03064% java InterfaceSample
add = 180
sub = 20

■インタフェースの特徴■

●内部には宣言だけしか記述できない ●メソッドには自動的に修飾子 abstract public が付けられる ●フィールドには自動的に修飾子 final public static が付けられる ●別のインタフェースを継承 (extends) できる ●実装クラスでは複数のインタフェースを実装 (implements) できる ●実装クラスではインタフェースの全ての宣言を実装する必要がある ●実装クラス型オブジェクトはインタフェース型に型変換される (インタフェース型変数に代入できる)

【参考文献・URL】

・浅煎り珈琲〜Java アプリケーション入門 (http://msugai.fc2web.com/java/#objective) ・JAVA言語入門 (http://black.sakura.ne.jp/~third/programming/java/java.html) ・Java入門 (http://www5c.biglobe.ne.jp/~ecb/java/java00.html)