プログラミング2
課題6

INDEX
課題詳細
static変数を用いたプログラム
static変数を共有させるプログラム
コンストラクタを用いた合計プログラム
staticイニシャライズを用いたプログラム
メソッドのオーバーロードを用いたプログラム
アクセス制御を用いたプログラム
クラスの継承
メソッドのオーバーライドを用いたプログラム
superを用いたクラスの継承
abstractを用いた抽象クラスと継承
interfaceとimplementsを用いたクラスの継承
感想
参考文献など

課題詳細

Report#6
11/15付講義資料と今回の講義資料中のサンプルプログラムについて考察せよ。

INDEXへ戻ります?


static変数を用いたプログラム

class Sum {
    int total;
    Sum() {
        total = 0;
    }
    void add(int x) {
        total += x;
    }
}

class SumSample {
    public static void main(String args[]) {

        Sum obj1 = new Sum();
        Sum obj2 = new Sum();

        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);
    }
}
[super:report06/kougi/1] J04011% java SumSample
obj1.total = 30
obj2.total = 70
考察
  1. コンストラクタについて。
    コンストラクタとは、
    1. 特定のクラスのオブジェクトを作成して初期化する特殊なメソッド
    2. 引数を受け取ることはできるが、戻り値は返さない。
    3. 戻り値を返さないが、作成したオブジェクトへの参照を行うことができる。
    4. コンストラクタとクラス名は同じである。(必ず)
    5. コンストラクタを呼び出すには常にnew演算子を用いる。
  2. 同じクラスを用いて、別々のオブジェクトを作る。 ソースのうち、クラスSumSample()に記述のある、
    Sum obj1 = new Sum();
    Sum obj2 = new Sum();
    のように、ひとつのクラスSum()から、obj1とobj2という全く別々のオブジェクトを作ることができる。
    もちろんこのふたつのオブジェクトは実行結果からもわかるように、それぞれが独立した値をもつことができる。

INDEXへ戻ります?


static変数を共有させるプログラム

class Sum {
    static int total;
    Sum() {
        total = 0;
    }
    void add(int x) {
        total += x;
    }
}

class SumSample {
    public static void main(String args[]) {
        Sum obj1 = new Sum();
        Sum obj2 = new Sum();

        obj1.add(10);
        obj1.add(20);
        obj2.add(30);

        System.out.println("obj1.total = " + obj1.total);
        System.out.println("obj2.total = " + obj2.total);

        obj2.add(40);

        System.out.println("obj1.total = " + obj1.total);
        System.out.println("obj2.total = " + obj2.total);
    }
}
[nw0411:report06/kougi/2] J04011% java SumSample
obj1.total = 60
obj2.total = 60
obj1.total = 100
obj2.total = 100
考察
  1. 1個目のソースでは、同一のクラスから作り出した別々のオブジェクトは、それぞれが独立した変数となっていたが、2個目のソースにあるように、
    static int total;
    と " static " を用いることで、変数totalを2つの別々のオブジェクトで『共有』することができる。

INDEXへ戻ります?


コンストラクタを用いた合計プログラム

class Sum {
    int total;
    Sum() {
        total = 0;
    }
    Sum(int x) {
        total = x;
    }
    void add(int x) {
        total += x;
    }
}

class ConstrcSample {
    public static void main(String args[]) {
        Sum obj1 = new Sum();
        obj1.add(10);
        obj1.add(20);
        System.out.println("sum1 = " + obj1.total);

        Sum obj2 = new Sum(100);
        obj2.add(10);
        obj2.add(20);
        System.out.println("sum2 = " + obj2.total);
    }
}
[nw0411:report06/kougi/3] J04011% java ConstrcSample
sum1 = 30
sum2 = 130
考察
  1. obj1はオブジェクトを生成した際、引数がないのが変数totalの初期値が0に指定されているのでobj1.add() が実行されると変数total = 10 + 20 = 30となる。 obj2はオブジェクトを生成した際、引数が100に指定されているので変数totalの値は100に初期化される。 それ故、obj2.add()が実行されると、total = 100 + 10 + 20 = 130 となる

INDEXへ戻ります?


staticイニシャライズを用いたプログラム

class Disp {
    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();
    }
}
[nw0411:report06/kougi/4] J04011% java StaticSample
initialize
construct
construct
考察
  1. このプログラムでは、staticイニシャライズを用いている。
    そのため、実際にプログラムが実行される際、
    Disp obj1 = new Disp();
    でクラスDispがロードされた際自動的に
    static {
    System.out.println("initialize");
    }
    が実行される。
  2. 結論。
    staticイニシャライズはコンストラクタとは違い、クラスがロードされた際に自動的に実行されるので、比較的コンストラクタよりも早い処理を行う事ができる。

INDEXへ戻ります?


メソッドのオーバーロードを用いたプログラム

class Display {
    void Disp() {
        System.out.println("Nothing");
    }
    void Disp(int x) {
        System.out.println(x);
    }
    void Disp(int x, int y) {
        System.out.println(x + y);
    }
}

class OvldSample {
    public static void main(String args[]) {
        Display obj = new Display();
        obj.Disp();    //引数無しでクラスDisplay内のメソッドDisp()を実行。
        obj.Disp(1);   //1を引数としてクラスDisplay内のメソッドDisp(int x)を実行。
        obj.Disp(1,2); //1、2を引数としてクラスDispla内のメソッドDisp(int x, int y)を実行。
    }
}
[nw0411:report06/kougi/5] J04011% java OvldSample
Nothing
1
3
考察
  1. ここでのソースにあるように、ひとつのクラスの中に同一の名前を持つメソッドを複数定義することをメソッドのオーバーロードという。
    メソッドのオーバーロードを用いるときは、それぞれの引数の数や型が必ず別のものでなければならない。

INDEXへ戻ります?


アクセス制御を用いたプログラム

class keisan {
    static int tanka;
    private float rate;
    keisan() {
        tanka = 1000;
        rate = 0.05f;
    }
    int keisan(int kazu) {
        int kingaku;
        kingaku = (int)(tanka * kazu * (1.0 + rate));
        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);
		/*rateはprivate変数のため参照不可。*/
    }
}
[nw0411:report06/kougi/6] J04011% java PrvSample
tanka = 1000
kazu = 3
kingaku = 3150
考察
  1. 変数を宣言するときに用いる修飾子の内、アクセス制御することのできる修飾子の特徴について。
    public全てのクラス、全てのメソッドからアクセス可能。
    private定義した同じクラスでのみアクセス可能。
    protected定義した同じクラスでのアクセス、そのクラスから派生したサブクラス、同じパッケージ内のクラスからアクセス可能。
  2. 上図に示した3つの修飾子は同時に使うことができない。
  3. 上記のソースにある
    //System.out.println("rate = " + obj1.rate);
    の文頭にある " // " を削除してコンパイルしてみたところ、
    [nw0411:report06/kougi/6] J04011% javac PrvSample.java
    PrvSample.java:25: rate は keisan で private アクセスされます。
            System.out.println("rate = " + obj1.rate);
                                               ^
    エラー 1 個
    というエラーメッセージがでた。
    これは、private修飾子のついた変数rateを、rateの定義されたクラスとは別のクラスの中で参照しようとしたためである。

INDEXへ戻ります?


クラスの継承

class Display {
    void Disp() {
        System.out.println("Hello! (^o^)/ ");
    }
}

class Succeed extends Display {
    public static void main(String args[]) {
        Succeed obj = new Succeed();
        obj.Disp();
    }
}
class Display {    //スーパークラス
    void Disp() {
        System.out.println("Hello! (^o^)/");
    }
}

class Override extends Display {  //サブクラス
    void Disp() { //メソッドのオーバーライド
        System.out.println("Hello! Java!! (^o^)/");
    }
    public static void main(String args[]) {
        Override obj = new Override();
        obj.Disp();
    }
}
[nw0411:report06/kougi/7] J04011% java Succeed
Hello! (^o^)/ 
[nw0411:report06/kougi/8] J04011% java Override
Hello! Java!! (^o^)/
考察
  1. 上記のソースにあるように、任意のクラスに、" extends 継承したいクラス名 " を付け加えることで、その任意のクラス(サブクラス)は、継承したいクラス(スーパークラス)を継承することができるようになる。
  2. スーパークラスを継承したサブクラス内で、
    1. スーパークラスと同じ名前のオブジェクトを定義。
    2. そのオブジェクトをスーパークラス内で利用。
    以上の条件を満たした状態をメソッドのオーバーライドという。
  3. 同じメソッドでも、後に定義された方が優先される。

INDEXへ戻ります?


メソッドのオーバーライドを用いたプログラム

class Display {      //スーパークラスDisplay
    void Disp() {
        System.out.println("Hello!");
    }
}

class SuperSample extends Display {  //サブクラスSuperSample
    void Disp() {                    //メソッドのオーバーライド
        super.Disp();                //スーパークラスのDispを実行。
        System.out.println("Hello! Java!! (^o^)/");
    }
    public static void main(String args[]) {
        SuperSample obj = new SuperSample();
        obj.Disp();                  //サブクラスのDispを実行。
    }
}
[nw0411:report06/kougi/9] J04011% java SuperSample
Hello!
Hello! Java!! (^o^)/
考察
  1. スーパークラスで定義されたメソッドをその下にあるサブクラスで呼び出したいときにsuperを使う。
  2. オーバーロードしたメソッドをサブクラス内で呼び出し、その中身を書き換えることもできる。
    このことより、メソッド内の機能を拡張させることができる。

INDEXへ戻ります?


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 ThisSample extends Keisan { //サブクラスThisSample
    public static void main(String args[]) {
        ThisSample obj = new ThisSample();
        obj.add(10, 20);
    }
}
class Keisann {
    void Keisann(int x, int y) {
        System.out.println("Keisann = " + (x * y));
    }
    void Keisann(int x) {
        this(x,1);
    }
}

class ThisSample1 extends Keisann {
    public static void main(String args[]) {
        Keisann obj1 = new Keisann(200,5);
        Keisann obj2 = new Keisann(200);
    }
}
[nw0411:report06/kougi/10] J04011% java ThisSample
w1 = 30 w2 = 120
[nw0411:report06/kougi/10] J04011% javac ThisSample1.java
ThisSample1.java:6: this の呼び出しはコンストラクタの先頭文でなければなりません。
        this(x,1);
            ^
ThisSample1.java:12: シンボルを解決できません。
シンボル: コンストラクタ Keisann (int,int)
場所    : Keisann の クラス
        Keisann obj1 = new Keisann(200,5);
                       ^
ThisSample1.java:13: シンボルを解決できません。
シンボル: コンストラクタ Keisann (int)
場所    : Keisann の クラス
        Keisann obj2 = new Keisann(200);
                       ^
エラー 3 個
考察
  1. thisについて。
    1. " this.変数名 " で、そのクラス(カレントクラス)内にある変数を参照するときに利用する。
    2. このような使い方で、同クラス内のメソッドで使われる全く同じ名前の変数でも使い分けることができる。
  2. 残念なことに2つ目のthisを用いたサンプルプログラムは3日間かけてコンパイルしようと心がけましたが、正直無理でした。
    きっとこのプログラムでやりたかったことは、
    1. まず、引数が一つのコンストラクタの x に 200 を引数として渡す。
    2. 次に、そのまま 200 と 1 を引数として、今度はオブジェクトobj1に引き渡して演算。
    3. 最後に、 x * y = 200 * 1 = 200 を出力してプログラム終了。

INDEXへ戻ります?


abstractを用いた抽象クラスと継承

abstract class PreDifine {
    public abstract int add(int x, int y);
    public int sub(int x, int y) {
        return x - y;
    }
}

class AbstractSample extends PreDifine {
    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));
    }
}
[nw0411:report06/kougi/11] J04011% java AbstractSample
add = 180
sub = 20
考察
  1. 抽象クラスについて。
    1. 先頭に、 " abstract " のついたクラスを抽象クラスと呼ぶ。
    2. インスタンス変数を含んでいたり、abstract宣言したメソッドを持つクラスにもついていなければならない。
      つまり、抽象クラスではオブジェクトを生成できない。
    3. 抽象クラスで定義した抽象メソッドは後にサブクラスを作り、そこでメソッドをオーバーライドして具体的に定義し直す必要がある。

INDEXへ戻ります?


interfaceとimplementsを用いたクラスの継承

こちらが正しいソース。
interface PreDefine {
    int add(int x, int y);
    int sub(int x, int y);
}

class InterfaceSample implements 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));
    }
}
[nw0411:report06/kougi/12] J04011% java InterfaceSample
add = 180
sub = 20
考察
  1. interfaceとimplementsについて
    1. interfaceとは、実際の定義をもたない抽象メソッドの集まりである。
      つまり、定義を後から自由に行えるので多人数でもプログラム開発に役立つ。
    2. 抽象クラスと同様に、抽象メソッドには戻り値と引数さえ与えてしまえば、すぐに定義部分を与える必要はない。
    3. abstractと同様、抽象メソッドから成り立つため、オブジェクトを生成することはできない。
    4. interfaceにあるメソッドを実装するためには、" implements " キーワードを用いて具体的に定義する必要がある。

INDEXへ戻ります?


感想

今回は課題内容が多いということが大きな問題となり、かなりの時間を費やしてしまいました。
実際、サンプルプログラムも後半、終わりが近づくにつれ間違いが多くなっていてとても苦戦しました。
atatic や init ならまだしも、implement にはなかなか間違いが気付かず大苦戦。
それでもひとつひとつプログラムを完成させるにつれて間違いの発見も早くなり、とてもプラスに出来たような気がします。
タイプ速度もはやくなったきもするし、プログラムの流れを掴むのもはやくなったので、満足できる内容になって良かったです。

INDEXへ戻ります?


参考文献など

独習Java 第2版

INDEXへ戻ります?


ひとつ前の画面に戻ります?
homeに戻ります?