Report#3

課題: 体積・表面積公式クラスの作成
(1)3種以上の体積を求めるクラスを作成し、具体的な値を入力しプログラムを実行せよ。
(2)2種以上の表面積を求めるクラスを作成し、同様に実行せよ。
(3)例題を参考に、階乗計算を再帰プログラムにより作成し、for文による階乗計算との違いを考察せよ。

INDEX

1. 錐体の体積を求めるクラス
2. 球と円柱の表面積を求めるクラス
3. 再帰を用いた階乗計算
4. 補足
5. 反省



1 錐体の体積を求めるクラス

錐体という立体の体積を求めます。
求めるのは円錐、三角錐、四角錐(底面は台形)の3つ。

作ったクラスは3つ。
まずはBottomクラスを作り、これに円と三角と台形の面積を求めるメソッドを入れる。
これがそれぞれの錐体の底面積になる。
次にそれを継承*したConeクラスを作成。
これに、底面積x高さ/3という円錐の体積を求めるメソッドを組み込む。
そして、それを実行するDemoクラスを作った。

ソース[Bottom.java]

01:public class Bottom { //円、三角、台形の面積を求める。
02:    float Area(int x){ //円の面積
03:        double pie =3.14;
04:        return (float)(x*x*pie);
05:    }
06:    float Area(int x,int y){ //三角形の面積
07:        return (float)(x*y/2);
08:    }
09:    float Area(int x,int y,int z){ //台形の面積
10:        return (float)((x+y)*z/2);
11:    }
12:}

解説[Bottom.java]

底面となる、円と三角と台形の面積を求めるメソッドを持つ。
3つのメソッドは引数の数がそれぞれ違うのでオーバーロード*してある。

02: float Area(int x){...}

円の面積を求めるメソッド。引数は半径xのみ。
円の面積の公式はπr^2
πは3.14にしてある。

06: float Area(int x,int y){...}

三角形の面積を求めるメソッド。引数は底辺xと高さy。
三角形の面積公式は底辺x高さ/2

09: float Area(int x,int y,int z){...}

台形の面積を求めるメソッド。引数は上辺x、下辺y、高さz。
台形の面積公式は(上辺+下辺)x高さ/2

ソース[Cone.java]

01:public class Cone extends Bottom {
02:    void Vol(int h, int x){ //円錐の体積
03:        System.out.println("底面の半径 " + x);
04:        System.out.println("錐の高さ " + h);
05:        System.out.println("の円錐の面積は "+ super.Area(x)*h/3);
06:    }
07:    void Vol(int h, int x,int y){ //三角錐の体積
08:        System.out.println("底面の底辺 " +x+ ", 高さ" +y);
09:        System.out.println("錐の高さ " + h);
10:        System.out.println("の三角錐の面積は "+ super.Area(x,y)*h/3);
11:    }
12:    void Vol(int h, int x,int y,int z){ //四角錐の体積
13:        System.out.println("底面の上辺 " +x+ ", 下辺" +y+ ", 高さ" +z);
14:        System.out.println("錐の高さ " + h);
15:        System.out.println("の四角錐の面積は "+ super.Area(x,y,z)*h/3);
16:    }
17:}

解説[Cone.java]

Bottomクラスを継承したクラス。
円錐、三角錐、四角錐の体積を求めるメソッドを持つ。
全て引数の数が違うのでこれもオーバーロードしてある。
それぞれのメソッドは、Bottomクラス内のAreaメソッドを使用する。

01:public class Cone extends Bottom {

Bottomクラスを継承したConeクラスを作成。

02: void Vol(int h, int x){...}

円錐の体積を求めるメソッドを定義。
Bottomクラス内の、引数が1つであるAreaメソッドを呼び出す。
super.Area()としているが、Area()だけでも呼び出す事は可能。
それに高さx1/3を掛けて、体積を求める。

07: void Vol(int h, int x,int y){...}

三角錐の体積を求めるメソッド。
ここでは、引数が2つのAreaメソッド(三角形の面積を求める)を呼び出している。

12: void Vol(int h, int x,int y,int z){...}

四角錐の体積を求めるメソッド。
ここでは、引数が3つのAreaメソッド(台形の面積を求める)を呼び出している。

ソース[Demo.java]

01:public class Demo {
02:    /**
03:     * 錐体の体積を求めるクラスのデモ
04:     */
05:    public static void main(String[] args) {
06:        Cone sui = new Cone();
07:
08:        System.out.println("- - - 円錐 - - -");
09:        sui.Vol(8,4);
10:        System.out.println("- - -三角錐- - -");
11:        sui.Vol(8,4,4);
12:        System.out.println("- - -四角錐- - -");
13:        sui.Vol(5,6,7,1);
14:    }
15:}

解説[Demo.java]

Coneクラスのオブジェクトを生成し、体積を求めるメソッドVolを呼び出す。

06: Cone sui = new Cone();

Coneクラスのオブジェクトsuiを生成する。
Volはインスタンスメソッドなのでまずオブジェクトを生成してから使用する。

09: sui.Vol(8,4);
11: sui.Vol(8,4,4);
13: sui.Vol(5,6,7,1);

それぞれ、
円錐の体積を求めるメソッドVol、
三角錐の体積を求めるメソッドVol、
四角錐の体積を求めるメソッドVolを呼び出す。

実行結果

[suzu-2:~/Documents/workspace/06eg] j06062% java Demo
- - - 円錐 - - -
底面の半径 4
錐の高さ 8
の円錐の面積は 535.8934
- - -三角錐- - -
底面の底辺 4, 高さ4
錐の高さ 8
の三角錐の面積は 21.333334
- - -四角錐- - -
底面の上辺 6, 下辺7, 高さ1
錐の高さ 5
の四角錐の面積は 35.0
[suzu-2:~/Documents/workspace/06eg] j06062% 



2 球と円柱の表面積を求めるクラス

球と円柱の表面積を計算するクラスCircleと、それを実行するクラスDemoを作った。

ソース[Circle.java]

01:public class Circle extends Bottom {
02:    final double pie =3.14;
03:    void Surf(int x){ //球の表面積
04:        System.out.println("半径 " + x);
05:        System.out.println("の球の表面積は "+ 4*pie*x*x);
06:    }
07:    void Surf(int h, int x){ //円柱の表面積
08:        System.out.println("底面の半径" +x+ ", 柱の高さ" +h);
09:        System.out.println("の円柱の表面積は "+ super.Area(x)*2 + Round(x)*h);
10:    }
11:    float Round(int x){ //円の円周
12:        return (float)(2*x*pie);
13:    }
14:}

解説[Circle.java]

球と円柱の表面積を求めるクラス。
円の公式を使うので、これも1で作ったBottomクラスを継承して作る。
引数の数がそれぞれ違うので、これらのメソッドはオーバーロードしてある。

01:public class Circle extends Bottom {

Bottomクラスを継承したCircleクラスを作る。

02: final double pie =3.14;

変数pieに3.14を代入。
これを円の計算でπの代わりとして使用する。
もう変更しない変数なので、final修飾子*をつけ、定数として扱う。

03: void Surf(int x){...}

球の表面積を求めるメソッド。
球の表面積は、4πr^2で求められる。

07: void Surf(int h, int x){...}

円柱の表面積を求めるメソッド。
円柱の表面積は、底面積x2+円周x高さで求められる。
super.Area(x)で底面積を求め、Round(x)*hで円周x高さを求めている。

11: float Round(int x){...}

円の円周を求めるメソッド。
半径を引数として受け取り、2*3.14*半径を返す。

ソース[Demo2.java]

ソース[Demo2.java]
01:public class Demo2 {
02:    /**
03:     * 球と円柱の表面積を求めるクラスのデモ
04:     */
05:    public static void main(String[] args) {
06:        Circle en = new Circle();
07:        System.out.println("- - - 球 - - -");
08:        en.Surf(3);
09:        System.out.println("- - -円柱- - -");
10:        en.Surf(6,3);
11:    }
12:}

解説[Demo2.java]

Circleクラスのオブジェクトを生成し、表面積を求めるメソッドSurfを呼び出す。

06: Circle en = new Circle();

Circleクラスのオブジェクトenを生成する。

08: en.Surf(3); 10: en.Surf(6,3);

それぞれ、 球の表面積を求めるメソッドSurf、 円柱の表面積を求めるメソッドSurfを呼び出す。

実行結果

[suzu-2:~/Documents/workspace/06eg] j06062% java Demo2
- - - 球 - - -
半径 3
の球の表面積は 113.03999999999999
- - -円柱- - -
底面の半径3, 柱の高さ6
の円柱の表面積は 226.08113.04
[suzu-2:~/Documents/workspace/06eg] j06062% 



3 再帰を用いた階乗計算

標準入力から自然数を取得し、その階乗を再帰プログラムによって求める。
その動作を見るため、自己を呼び出した回数を表示する。
まずは実行結果から。

実行結果

[suzu-2:~/Documents/workspace/06eg] j06062% java Factorial
input natural number: 6
call Factorial [6]
call Factorial [5]
call Factorial [4]
call Factorial [3]
call Factorial [2]
call Factorial [1]
720
[suzu-2:~/Documents/workspace/06eg] j06062% 

ソース

01:import java.io.*;
02:
03:public class Factorial {
04:    /**
05:     * 階乗計算の再帰プログラム
06:     */
07:    public static void main(String[] args) throws IOException{
08:        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
09:        System.out.print("input natural number: ");
10:        int num = (new Integer(in.readLine())).intValue();
11:        System.out.println(Fact(num));  
12:    }
13:    static int Fact(int x){
14:        System.out.println("call Factorial [" +x+ "]");
15:        if (x == 1) return(1);
16:        else return (x * Fact(x-1));
17:    }
18:}

解説

01:import java.io.*;

入出力に関係するパッケージ名を省略する。

07: public static void main(String[] args) throws IOException{

mainメソッドを作成。
メソッド内で入出力の例外が起きた時は呼び出し側にエラーを投げる。

08: BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
10: int num = (new Integer(in.readLine())).intValue();

標準入力から文字列を読み取り、int型の変数numに代入する。

11: System.out.println(Fact(num));

numを引数としてFact()を呼び出し、返された値を表示する。

13: static int Fact(int x){

staticメソッドFact()を作る。
staticをつけたメソッドは静的メソッドになり、インスタンス化しなくても実行できる。

14: System.out.println("call Factorial [" +x+ "]");

呼び出した回数を確認するため、引数xを表示。

15: if (x == 1) return(1);

xが1であれば値1を返す。

16: else return (x * Fact(x-1));

xが1でないなら、x*fact(x-1)を返す。 fact(x-1)とする事で、自分自身を呼び出す。

再帰プログラム

プログラムの中で、自分自身を呼び出す構造の事。
この階乗計算プログラムにおいて、6を入力した場合の処理の概要を下に示す。

図

Fact(6)=6*Fact(5)で、Fact(5)=5*Fact(4)で、Fact(4)=4*Fact(3)で・・・
という風に、Fact(n)を求めるためにFact(n-1)を呼び出す作業を繰り返す。
この場合、
if (x == 1) return(1);
とあるので、Fact(1)=1になり、ここで再帰がストップする。
このように、どこかで再帰を止めないと、延々と自分自身を呼び出し続ける事になる。

階乗計算など単純な計算ではfor文で記述するのと大差ないが、
フィボナッチ数を求める際などには、for文よりもアルゴリズムがわかりやすく記述できる。


4. 補足

用語

継承

・あるクラスのメソッドや変数を引き継いだ他のクラスを作る方法。
・元になるクラスをスーパークラス、それを継承した新しいクラスをサブクラスという。
 一つのクラスは、一つのスーパークラスしか持てない。
 javaにおいて、全てのクラスはObjectクラスのサブクラスである。
・定義にはextendsというキーワードを使う。
 class Name extends SuperName {...}
 と書くと、SuperNameクラスのサブクラスNameを生成する。

オーバーロード

・同一クラス内でメソッド名が同じだが、変数型・数・並び順が異なるメソッドを複数定義する事。
・そのメソッドを呼び出す時は、引数の型や数や並び順が一致するメソッドが呼び出される。

final修飾子

・変数にfinalをつけると、その変数は初期値で指定した値から変更できなくなる。
・メソッドにfinalをつけると、そのメソッドは他のメソッドでオーバーライド*できなくなる。
・クラスにfinalをつけると、そのクラスは他のクラスに継承できなくなる。
 -> その他の修飾子について

オーバーライド

・スーパークラスにおいて定義されているメソッドと、同じ名前・引数(つまり同じシグネチャ*)を持つメソッドを定義する事。
・スーパークラスの同名メソッドを呼び出すときはsuper.MethodName()とする。
・オーバーロードと紛らわしいんですが、オーバーライドは上乗せとか上書きの意味があると覚えてみる。

シグネチャ

・メソッド名とメソッドの戻り値や引数全体の事。
・メソッドのオーバーライドは、シグネチャが同じメソッドをサブクラスで定義する事。




5. 反省

今回は色々なテストと衝突(コリジョン)が起きたため、このように更新が遅れる結果となりました。
この課題は、やってみると再帰プログラム以外はほとんど解説する事が無いのにびっくりです。
それではまずいので無理矢理継承を使ってみました。
単に継承を解説したかっただけです。
おかげで微妙に不自然な構成になってます。
おまけで修飾子リストを作ってみましたが、これは備忘録みたいなものです。
テストで修飾子は結構出たので、後々大事になりそうです。
それから、次の目標としては…とりあえずページレイアウトの欠陥が見え始めたので、そっちも直していこうと思います。