Report6


@11/15付講義資料と今回の講義資料中のサンプルプログラムについて考察せよ。
講義資料サンプルプログラム考察については、static変数以降とする。

■static変数(1)

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変数(2)

class Sum2 {
static int total; // 値を共有させる
Sum2() { // コンストラクタ(クラス名と同名)
total = 0; // 0 クリア
}
void add(int x) {
total += x;
}
}

class SumSample2 {
public static void main(String args[]) {
Sum obj1 = new Sum2(); // クラスSumのオブジェクトobj1生成
Sum obj2 = new Sum2(); // クラス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

〜考察〜

1.static変数は関数やブロック内で宣言された変数である。そのブロックが終了しても値を保持しているもの。
   静的変数ともよばれる。生成されたオブジェクトの個数や状態をそのブロック内に格納しておく変数として使うと便利である。
  グローバル変数のように、他の関数から使用することはできない。
2.二つのプログラムの違いはstatic変数を使っているかいないかの違いである。
	a.プログラム1はint型で変数totalを定義し、3行目でコンストラクタを作成。
  class Sumsample{}の中で、クラスSumのオブジェクトobj1,obj2を生成し、obj1とobj2に数字を入れ計算する。
b.変数totalがobj1とobj2で区別されているので、obj1とobj2の中に入れられた数字をそれぞれ計算して出力する。
c.プログラム2はstatic int totalで値を共有させる変数totalを定義。
  その他は一つ目のプログラムと同じだが、int型変数obj1.totalとobj2.totalは同じ変数totalを指しているので   obj1とobj2で区別無く加算される。
 

■コンストラクタ

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

〜考察〜

1.コンストラクタはクラス名と同じ名前のメソッドのことである。 
 a.コンストラクタはオブジェクトの初期化処理に利用できる。
b.引数をうけとることができるが、戻り値を返すことはできない。
c.コンストラクタを直接呼び出すことはできない。常にnew演算子で呼び出さなければならない。 2.コンストラクタSumはオブジェクト作成したときに引数があればtotalにその値を代入し、無ければ0をtotalに代入する。 3.sum1とsum2の結果が違うのはsum2にはオブジェクトを作成したときに引数100がtotalに代入されているからである。

■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(); // オブジェクト生成時にコンストラクタを処理
Disp obj2 = new Disp(); // オブジェクト生成時にコンストラクタを処理
}
}

※実行結果
initialize ※ Dispクラスのロード時に処理
construct ※ Disp.obj1 = new Disp(); が実行されるときに処理
construct ※ Disp.obj2 = new Disp(); が実行されるときに処理

〜考察〜

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

2.プログラムでもDispコンストラクタの前にstaticイニシャライズが記述されている。

3.Dispをインスタンス化した際に最初のコンストラクタを処理する前にstaticイニシャライズが実行される。
  a. しかし、次のobj2を作成したときには実行されてないことがわかる。
   これはstaticイニシャライズが一回しか実行しないことを示す。
4.このプログラムではstaticイニシャライズでinitializeをDispコンストラクタにてconstructを文字列出力するものである。

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

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)を実行
}
}

※実行結果
Noting
1
3

〜考察〜

1.オーバーロードとは同じメソッド名で、引数リストの異なるメソッドを同時に定義すること。
 a.このプログラムでは3つのDisppメソッドがオーバーロードの関係にある。
  b.引数なしの場合Nothingが文字列出力される。
 c.引数が1つ指定されたらその引数を出力する。
 d.引数が2つ指定されたらその2つの引数を加算し、結果を出力する。
2.引数の組まで同じにするとコンパイルエラーになる。
  a.メソッド名も引数の型の組も同じにすると、呼び出し時にどちらを実行してよいか分からなくなるからである。
3.オーバーロードされたメソッドは別のメソッドとして区別されるので、戻り値型や修飾子などは任意のものが指定できる。

■アクセス制御

class keisan {
atatic int tanka;
private float rate; // private変数rateの宣言
keisan() { // コンストラクタ
tanka = 1000;
rate = 0.05f;
}
init 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); //private変数のため参照不可
}
}

※実行結果
tanka = 1000
kazu = 3
kingaku = 3150

〜考察〜

1.クラス、メンバ変数(フィールド)、メソッド、コンストラクタには修飾子を指定できる。
  a.それぞれに指定できる修飾子は異なり、言語仕様として定義されている。
2.アクセス制御する修飾子
public:全てのオブジェクトの全てのメソッドからアクセス可能
private:定義されたクラス内のメソッドからだけアクセス可能
protected:定義されたクラス内のメソッド、そのクラスから派生したサブクラス、同一パッケージ内のクラスからアクセス可能
3.プログラムの中身はkeisanメソッドを呼び出してkingakuに単価1000×引数3(1.0+rate0.05)を代入。

 a.tankaとkazuとkingakuを出力する。
  b.23行目はrateがprivateで定義されているため参照できないことからコメントアウトされている。

■継 承(1)

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!

■継 承(2)

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!!

〜考察〜

1.継承 (extends) とは、あるクラスの実装を土台にして、別のクラスを実装するための方法。
  元になるクラスをスーパークラスと呼び、それを継承する新しいクラスをサブクラス(継承クラス)と呼ぶ。
 a.プログラム1では、Displayがスーパークラス、Succeedがサブクラス。
  b.サブクラスはスーパクラスの性質を全て備えている。
2.一つのクラスは、任意の個数のサブクラスを持つことが出来るが、逆に、スーパークラスは一つしか持てない。
3.既存のクラスから派生したクラスを作成する時は、クラス定義時に extends キーワードを記述する。
☆オーバーライドについて
1.オーバーライドとは継承時に、スーパークラスで定義されたメソッドと同じ名前、引数を持つメソッドを、
 サブクラスでもう一度定義すること。
2.プログラム2ではメソッドのオーバーロードを行っているため、実行結果がHello! Java!!となっている。

■super

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!!

〜考察〜

1.superはオーバーライドされたスーパークラスのメソッドの方を呼び出す。
  a.superを使うときはメソッドの前にsuper.を記述すれば良い。
    b.superはsuperが置かれているクラスのスーパークラスのオブジェクトを表す。
2.このプログラムではDisplayを継承したサブクラスSuperSampleのなかで、
  super.Disp()でスーパークラスのDispを実行している。

■this(1)

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 Display { // サブクラス ThisSample1
public static void main(String args[]) { // メソッド
ThisSample1 obj = new ThisSample1(); // オブジェクト生成
obj.add(10, 20); // add 実行
}
}

※実行結果
w1 = 30 w2 = 120

 

■this(2)


class Keisan {
void Keisan(int x, int y) { // 引数が二つのコンストラクタ
System.out.println("Keisan = " + (x * y));
}
void Keisan(int x) { // 引数が一つのコンストラクタ
this(x, 1); // Keisan(x, 1)と同じ
}
}

class ThisSample2 extends Display { // サブクラス ThisSample2
public static void main(String args[]) { // メソッド
Keisan obj1 = new Keisan(200, 5); // 引数が二つのコンストラクタ実行
Keisan obj2 = new Keisan(200); // 引数が一つのコンストラクタ実行
}
}

※実行結果
Keisan = 1000
Keisan = 200

〜考察〜

1.thisはカレントクラスを参照するときに利用する。  
    a.クラス変数と同クラス内のメソッド変数が同じ名前の時、
     ・ただ変数を記述しただけではメソッド変数が優先される。
    ・クラス変数はthis.を付けて使い分けることが可能である。
    b.thisはメソッド自身を指し示す事も可能である。
2.プログラム1においてw1とw2の結果が違うのは、
     ・w1は引数10がxに代入されたのに対し、
          ・w2はthis.を用いた事によりクラス変数の100がxに代入されたからである。
3.プログラム2において結果が違うのは、
 		  ・引数が二つのコンストラクタの場合、Keisanは二つの引数を掛け算した結果であるのに対し、
		  ・引数が一つのコンストラクタの場合、Keisanはその引数×1の結果(つまり引数自身)であるからである。
  a.ここで引数が一つのコンストラクタのときにthisを用いてKeisanメソッドを呼び出している。
  b.Keisan(200)はKeisan(200,1)と同じなのである。

■abstract

public 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

〜考察〜

1.abstract宣言された抽象メソッドは不完全なメソッドである。
  a.抽象メソッドはメソッド名と引数、戻り値の型の宣言だけ行う。
   b.抽象メソッドを持つクラスは抽象クラスと呼び、abstract宣言しなければならない。
2. 抽象クラスは継承され、サブクラスでオーバーライドされる事によりメソッドの実装を果たすことができる。
  a.抽象クラスはインスタンス化できない。
   b.実装を果たした上でインスタンス化される。
3.このプログラムでは抽象クラスPreDefineを継承したAbstractSampleでaddメソッドを定義している。
   a.次にオブジェクトを作成し、printlnのなかでaddメソッドとsubメソッドを呼び出して出力している。

■interface


public interface PreDefine { // インタフェース PreDefine
int add(int x, int y); // 抽象メソッド add
int sub(int x, int y); // 抽象メソッド sub
}

class InterfaceSample implement 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

〜考察〜

1.インターフェースとは内容に抽象メソッドしか持たないクラスのようなものである。
   a.クラスと並んで、パッケージのメンバーとして存在する。
   b.インタフェースはクラスによって実装(implements)され、
     実装クラスはインタフェースで宣言されている抽象メソッドを実装する。
  c.クラスの場合は、単一のクラスしか継承(extends)できないが、
  インタフェースの場合は、複数のインタフェースを実装(implements)することができる。
2.プログラムの内容は、
  a.インターフェースPreDefineの中で抽象メソッドaddメソッド、subメソッドを定義。
   b.PreDefineをインプリメントしたクラスInterfaceSampleのなかでaddメソッド、subメソッドを具体的に定義。
  c.addメソッドは二つの引数を加算しその結果を返す。
  d.subメソッドは二つの引数を減算しその結果を返す。
  e.オブジェクトを作成し、二つのメソッドを呼び出す。
   d.printlnで結果を出力。

 

〜反省&感想〜

 今回のプログラムは結構理解できたと思います。いろんなページで勉強してきました。
 
 すいません。遅くなりました。...年末に終わらそう♪としてたらずるずると正月を迎えてしまいました。
風邪もひくし散々な正月です(^^;)。今年はレポートためないぞ!てかreport5とreport7を早めにかたずけます。

参考文献等

     a.独習Java 〜第二版〜
     b.浅煎珈琲 Javaアプリケーション入門 http://msugai.fc2web.com/java/index.html