オブジェクト指向の応用問題1-2
問題3-7
スレッドによる走行を表現するRacingCarクラスを作成してください。
RacingCarクラスを使用するThreadBasicPracticeクラスのmainメソッドは完成しています。
(変更は禁止です)
【RacingCarクラス】
Threadクラスを継承します。
ゴール地点までの距離を表すint型の定数GOALを定義します。
定数GOALの値は100を代入して初期化してください。RacingCarクラスは次の3つのインスタンスフィールドを持ちます。
車の名前を表すname(String型)
その車の最高走行距離を表すmaxDistance(int型)
その車のエンストする割合を表すengineStop(int型)次の引数を持つコンストラクタを1つ作成してください。
第1引数 車の名前を表すString型の引数
第2引数 最高走行距離を表すint型の引数
第3引数 エンストする割合を表すint型の引数runメソッドをオーバーライドします。2つのローカル変数を宣言します。
総走行距離を表すint型 totalMileage
一回の走行距離を表すint型 mileageランダムの雰囲気を出すために、java.utilパッケージのRandomクラスを使用します。
【Randomクラスの使い方の例】
Random r = new Random();
System.out.println(r.nextInt(6) + 1);
これで1〜6を表示するさいころの出来上がりです。runメソッドでは、ゴールするまで走行します。
まず、エンストするかどうかをRandomクラスを使って表現します。
engineStopの値が10なら、10回に1回の割合でエンストします。
エンストした場合は「○○がエンストしました!」と表示獅子、3秒間停止します。
エンストしなかった場合は走行します。
走行距離は、1から最高走行距離maxDistanceの間のランダムな値です。
そして「○○が△△km走行しました!」と表示します。
総走行距離がGOAL定数を超えていればループを抜けて「○○がゴールしました!!!!!」と表示して終了します。
まだ総走行距離がGOAL定数に達していなければ1秒停止して走行を続けます。
【実行結果の一例】
Careful号が3km走行しました! Normal号がエンストしました! Normal号が3km走行しました! ・・・ Careful号が2km走行しました! Gambler号が15km走行しました! Gambler号がゴールしました!!!!! Careful号が4km走行しました! Normal号が8km走行しました! Careful号が1km走行しました! Careful号が4km走行しました! Careful号がゴールしました!!!!! Normal号が8km走行しました! Normal号がゴールしました!!!!! レースが終了しました
【ThreadBasicPractice.java】
public class ThreadBasicPractice { public static void main(String[] args) { // 平均的な性能のnormal号 RacingCar normal = new RacingCar("Normal号", 10, 10); // スピードはあるがエンストが多いgambler号 RacingCar gambler = new RacingCar("Gambler号", 20, 3); // 安全面を重視したcareful号 RacingCar careful = new RacingCar("Careful号", 5, 1000); // 各車一斉にスタート!! normal.start(); gambler.start(); careful.start(); // 前車がゴールするのを待つ try { normal.join(); gambler.join(); careful.join(); } catch(InterruptedException e) { e.printStackTrace(); } System.out.println("レースが終了しました"); } } // ここにRacingCarクラスを作成してください
問題3-8
5人の大富豪が1つの募金箱に同時に募金していく様子をシミュレートしています。
大富豪を表現するMultiMillionaireクラスと、募金箱を表現するCollectionBoxクラスを作成してください。
また、これらのクラスを使用するThreadSafePracticeクラスのmainメソッドは完成しています。
(変更は禁止です)
【MultiMillionaireクラス】
Threadクラスを継承します。
募金箱インスタンスフィールドを定義します。
募金箱オブジェクトを引数に受け取るコンストラクタを定義します。
runメソッドをオーバーライドします。
for文を用いて100万回ループさせます。
for文の中では、募金箱に対して1円を募金します。
(1円募金×100万回ループなので、100万円寄付することになります)
【CollectionBoxクラス】
募金総額を表すインスタンスフィールドtotalAmout(int型)を定義します。
募金箱オブジェクトは、絶対に1つだけしか存在しないようにしてください。
・別クラスからインスタンス化できないようにコンストラクタを工夫してください。
・クラスメソッドgetInstanceを用いて、募金箱オブジェクトを取得してください。
・CollectionBox型のクラスフィールドを定義して、うまく利用してください。お金を寄付するためのcontributeメソッドを定義してください。
引数は寄付する金額(int型)で、戻り値はなしにします。
このメソッドをスレッドセーフにするように注意してください。募金総額を取得するためのgetTotalAmoutメソッドを定義してください。
引数はなしで、戻り値に募金総額フィールドの値を返してください。
ただし、最後に表示する募金総額には絶対にずれが生じないようにしてください。
【正しい実行結果】
募金総額は5000000円です。
【正しくない実行結果(不定)】
募金総額は3294875円です。
【ThreadSafePractice.java】
public class ThreadSafePractice { public static void main(String[] args) { // 募金箱オブジェクトの取得 CollectionBox cb = CollectionBox.getInstance(); // 偽物の募金箱を作れないようにする(コンパイルエラー) // CollectionBox imitation = new CollectionBox(); // 5人の大富豪オブジェクトを生成 MultiMillionaire mm1 = new MultiMillionaire(cb); MultiMillionaire mm2 = new MultiMillionaire(cb); MultiMillionaire mm3 = new MultiMillionaire(cb); MultiMillionaire mm4 = new MultiMillionaire(cb); MultiMillionaire mm5 = new MultiMillionaire(cb); // 募金の開始 mm1.start(); mm2.start(); mm3.start(); mm4.start(); mm5.start(); // 全員の募金が終わるまで待つ try { mm1.join(); mm2.join(); mm3.join(); mm4.join(); mm5.join(); } catch(InterruptedException e) { e.printStackTrace(); } // 募金総額の発表 System.out.println("募金総額は" + cb.getTotalAmout() + "円です。"); } } // ここに大富豪クラスを作成してください // ここに募金箱クラスを作成してください
問題3-9
学校を表現するSchoolクラスと、その学校に在学する生徒を表現するStudentクラスを作成してください。
ただし、StudentクラスはSchoolクラスの中だけで使えるprivateな非staticネストクラスにしてください。
Schoolクラスを使用するNestClassBasicPracticeクラスのmainメソッドは完成しています。
(変更は禁止です)
【Schoolクラス】
定員人数を表現するint型の定数CAPACITYを宣言します。
初期値に「5」を設定してください。次の2つのインスタンスフィールドを持ちます。
・学校名を表すname(String型)インスタンスフィールド
・在校生を表す配列students(Student[]型)インスタンスフィールドコンストラクタでは引数として学校名(String型)を受け取ります。
そのままインスタンスフィールドに値を格納してください。
また、このタイミングで定員人数分の在校生配列オブジェクトを生成します。入学メソッドenterSchoolを定義します。
引数は生徒名で、在校生配列の先頭から空き(つまりnull)を検索し、空きがあればStudentクラスのインスタンスを生成して配列要素として格納します。
出席番号は1から順に割り当てます。
その際に「○○さんが△△に入学しました」と出力してください。
もし定員人数を超えてしまう場合は「定員オーバーで○○さんは△△に入学できません」と表示して入学を見送ります。在校生紹介メソッドintroduceを定義します。
在校生配列の先頭から、在校生がいれば(つまりnullでなければ)toStringメソッドを呼び出して自己紹介させます。privateな非staticネストクラスStudentを定義します。
【Studentネストクラス】
次の2つのインスタンスフィールドを持ちます。
・出席番号を表すid(int型)インスタンスフィールド
・生徒名を表すname(String型)インスタンスフィールドコンストラクタでは引数として出席番号(int型)と生徒名(String型)を受け取ります。
そのままインスタンスフィールドに値を格納してください。toStringメソッドをオーバーライドして、自己紹介文を戻り値として返します。
実装は下記実行結果を参考にしてください。
【実行結果】
春日さんがJava学園に入学しました 若林さんがJava学園に入学しました 遠藤さんがJava学園に入学しました 田中さんがJava学園に入学しました 渡辺さんがJava学園に入学しました 定員オーバーで山下さんはJava学園に入学できません Java学園に在学している出席番号1の春日です。 Java学園に在学している出席番号2の若林です。 Java学園に在学している出席番号3の遠藤です。 Java学園に在学している出席番号4の田中です。 Java学園に在学している出席番号5の渡辺です。
【NestClassBasicPractice.java】
public class NestClassBasicPractice { public static void main(String[] args) { // 学校の設立 School school = new School("Java学園"); // 生徒が続々と入学 school.enterSchool("春日"); school.enterSchool("若林"); school.enterSchool("遠藤"); school.enterSchool("田中"); school.enterSchool("渡辺"); // 定員オーバー school.enterSchool("山下"); System.out.println(); // 在校生の紹介 school.introduce(); } } // ここに学校クラスを作成してください // さらに、生徒ネストクラスを作成してください
問題3-10
四季を表現するSeason列挙型を作成してください。
【Season列挙型】
Season列挙型は4つの列挙子(SPRING、SUMMER、FALL、WINTER)を持ちます。
Season列挙型はprivateなインスタンスフィールドname(String型)を持ち、4つの列挙子に対して「春」「夏」「秋」「冬」という文字列を保持します。
(コンストラクタをうまく利用してください)toStringメソッドをオーバーライドして、インスタンスフィールドnameの情報を返してください。
また、EnumBasicPracticeクラスのmainメソッドは一部未完成です。
以下のように実装してください。
mainメソッド内で四季列挙子を格納した配列変数を宣言しています。
拡張for文を使ってすべての季節の列挙子をうまく使って表示してください。
ただし、SUMMERの場合は「夏は暑い!!」、WINTERの場合は「冬は寒い!!」という情報を表示するように工夫してください。
【実行結果】
春 夏は暑い!! 秋 冬は寒い!!
【EnumBasicPractice.java】
public class EnumBasicPractice { public static void main(String[] args) { // 四季列挙子を格納した配列変数の宣言 Season[] seasons = { Season.SPRING, Season.SUMMER, Season.FALL, Season.WINTER }; // 四季をループで回す } } // ここに季節列挙型を作成してください
問題3-11
小学生を表現するSchoolChildクラスは、不完全です。
また、小学生クラスを使用するCompareBasicPracticeクラスのmainメソッドも不完全です。
CompareBasicPracticeクラスは以下の部分でコンパイルエラーになります。
Collections.sort(classroom);
Collectionsユーティリティクラスのsortメソッドは、引数で渡されたList型の要素をソートします。
しかし、不完全なためソートできません。
次の指示に従って、2種類のソートを可能にしてください。
【SchoolChildクラス】
「順序の基準」を設定するために、SchoolChildクラスにComparable
このインタフェースは、compareToという抽象メソッドがあるので、適切に実装してください。
ただし、整列のルールは「出席番号の小さい順」にします。
【CompareBasicPracticeクラス】
Collectionsユーティリティクラスのsortメソッドには、第二引数に「特別な順序の基準」を設定するためのComparator
このインタフェースをそのままインスタンス化することはできませんが、無名(匿名)クラスを利用することで可能となります。
このインタフェースが持つcompare抽象メソッドを、無名クラスで実装してください。
ただし、整列のルールは「身長の高い順」にします。
【実行結果】
整列前 出席番号:4 名前:武藤 身長:145.0 出席番号:2 名前:佐藤 身長:130.0 出席番号:5 名前:加藤 身長:162.5 出席番号:1 名前:伊藤 身長:155.3 出席番号:3 名前:江藤 身長:151.1 出席番号順 出席番号:1 名前:伊藤 身長:155.3 出席番号:2 名前:佐藤 身長:130.0 出席番号:3 名前:江藤 身長:151.1 出席番号:4 名前:武藤 身長:145.0 出席番号:5 名前:加藤 身長:162.5 身長の高い順 出席番号:5 名前:加藤 身長:162.5 出席番号:1 名前:伊藤 身長:155.3 出席番号:3 名前:江藤 身長:151.1 出席番号:4 名前:武藤 身長:145.0 出席番号:2 名前:佐藤 身長:130.0
【CompareBasicPractice.java】
import java.util.*; // CompareBasicPracticeは未完成です public class CompareBasicPractice { public static void main(String[] args) { // 小学生たちがいる教室を表現するArrayList型変数 ArrayList<SchoolChild> classroom = new ArrayList<SchoolChild>(); // 5人の生徒が教室にいます classroom.add(new SchoolChild(4, "武藤", 145.0)); classroom.add(new SchoolChild(2, "佐藤", 130.0)); classroom.add(new SchoolChild(5, "加藤", 162.5)); classroom.add(new SchoolChild(1, "伊藤", 155.3)); classroom.add(new SchoolChild(3, "江藤", 151.1)); // 生徒たちの情報を表示(整列前) System.out.println("整列前"); for(SchoolChild sc : classroom) { System.out.println(sc); } System.out.println(); // 先生からの指示「出席番号順に整列しなさい」 Collections.sort(classroom); // 生徒たちの情報を表示(出席番号順) System.out.println("出席番号順"); for(SchoolChild sc : classroom) { System.out.println(sc); } System.out.println(); // 先生からの指示「身長の高い順に整列しなさい」 Collections.sort(classroom); // 生徒たちの情報を表示(身長の高い順) System.out.println("身長の高い順"); for(SchoolChild sc : classroom) { System.out.println(sc); } } } // 小学生クラスは未完成です class SchoolChild { private int no; // 出席番号 private String name; // 名前 private double height; // 身長 // コンストラクタ public SchoolChild(final int no, final String name, final double height) { this.no = no; this.name = name; this.height = height; } // 出席番号の取得 public int getNo() { return no; } // 名前の取得 public String getName() { return name; } // 身長の取得 public double getHeight() { return height; } @Override public String toString() { return "出席番号:" + no + " 名前:" + name + " 身長:" + height; } }
問題3-12
ホテルを表現するHotelクラスを作成してください。
そのホテルに勤務するStaffクラスと、そのホテルを利用するCustomerクラスも作成してください。
また、人を表現するPerson抽象クラスと、労働可能を表現するWorkableインタフェース、所持金不足を表現するShortFallException例外クラスは完成しています。
(変更は禁止です)
これらのクラスを使用するTotalHiLevelPracticeクラスのmainメソッドも完成しています。
(変更は禁止です)
【Hotelクラス】
次の4つのインスタンスフィールドを持ちます。
ホテル名 name(String型)
利益 profits(long型)
従業員たち staffs(ArrayList型)
お客様たち customers(ArrayList型) 部屋のランクを表現するネストRoomRank列挙型を定義します。
(詳細は後に説明します)コンストラクタを持ちます。
引数はホテル名なので、フィールドに渡します。
「○○がオープンしました」と出力します。
そのあと、従業員たちとお客様たちを表現するArrayListオブジェクトをインスタンス化します。ホテルに入るenterメソッドをオーバーロードして2つ定義します。
引数が従業員の場合は、出勤です。
「○○が△△に出勤しました」と出力し、従業員たちArrayListオブジェクトに追加します。
引数がお客様と部屋ランクの場合は、宿泊希望です。
部屋ランク列挙型は価格を取得するgetPriceメソッド(戻り値int型)を持っているので、その値をお客様が持っているpayメソッドの引数に渡し、お金を支払ってもらいます。payメソッドの戻り値をホテルの利益フィールドに加算します。
「○○様が□□の▽▽にお泊まりになります」と表示し、最後にお客様たちArrayListオブジェクトに追加します。
なお、payメソッドは所持金が足りない場合にShortFallException例外をスローします。
例外オブジェクトの持つメッセージを出力してください。ホテル運営manageメソッドを定義します。
現在ホテルにいるすべての従業員の働くworkメソッドを実行します。
ただし、ループには拡張for文を使用してください。お客様の情報を出力するshowCustomerInfoメソッドを定義します。
「お客様情報」と出力した後に、現在ホテルにいるすべてのお客様の情報(toStringメソッドの戻り値)を出力します。
ただし、ループには拡張for文を使用してください。ホテル情報を出力するshowHotelInfoメソッドを定義します。
ホテル名や現在の従業員数、現在のお客様数、現在の利益などを出力します。
下記、実行結果を参考にしてください。
【ネストRoomRank列挙型】
ホテルクラスのメンバとして定義します。
3つの列挙子を持ちます。
また、2つのインスタンスフィールドとして部屋のランク名roomRankName(String型)と価格price(int型)を持ちます。
コンストラクタをうまく使ってフィールドに値を設定します。
列挙子「SUITE」 部屋のランク名「"スイートルーム"」 価格「100000」
列挙子「NORMAL」 部屋のランク名「"通常ルーム"」 価格「20000」
列挙子「ECONOMY」 部屋のランク名「"格安ルーム"」 価格「5000」価格を取得するgetPriceメソッドを定義します。
(引数なし・戻り値int型)toStringメソッドをオーバーライドします。
roomRankNameフィールドの値を返します。
【Staffクラス】
Personクラスを継承し、Workableインタフェースを実装します。
職種を表すjobTypeフィールド(String型)を定義します。
コンストラクタは第一引数に氏名、第二引数に職種を受け取ります。
フィールドに値をセットしてください。働くworkメソッドを実装します。
「○○が□□を行いました」と出力します。
【Customerクラス】
Personクラスを継承します。
所持金を表すmoneyインスタンスフィールド(int型)を定義します。
コンストラクタは第一引数に氏名、第二引数に所持金を受け取ります。
フィールドに値をセットしてください。支払payメソッドを定義します。
引数は使用金額(int型)なので、その分所持金から金額を差し引き、戻り値として返します。
所持金が足りない場合は、「○○は所持金不足です」というメッセージをShortFallException例外クラスの公司と楽に渡して、そのままスローします。お客様情報を返すtoStringメソッドをオーバーライドします。
「○○様 所持金:☆☆円」という文字列を返します。
【実行結果】
ホテルドルフィンがオープンしました 坂本がホテルドルフィンに出勤しました 長野がホテルドルフィンに出勤しました 井ノ原がホテルドルフィンに出勤しました 岡田様がホテルドルフィンのスイートルームにお泊まりになります 三宅様がホテルドルフィンの通常ルームにお泊まりになります 森田は所持金不足です 坂本が清掃を行いました 長野が調理を行いました 井ノ原が接客を行いました お客様情報 岡田様 所持金:400000円 三宅様 所持金:20000円 ホテルドルフィンの現在の状況 現在働いている従業員数:3名 現在お泊まりのお客様数:2名 現在の利益:120000円
【TotalHiLevelPractice.java】
import java.util.*; public class TotalHiLevelPractice { public static void main(String[] args) { // ホテルがオープン Hotel hotel = new Hotel("ホテルドルフィン"); // ホテルに3人の従業員が出勤 hotel.enter(new Staff("坂本", "清掃")); hotel.enter(new Staff("長野", "調理")); hotel.enter(new Staff("井ノ原", "接客")); System.out.println(); // 3人のお客様がチェックイン(1人が所持金不足で泊まれず) hotel.enter(new Customer("岡田", 500000), Hotel.RoomRank.SUITE); hotel.enter(new Customer("三宅", 40000), Hotel.RoomRank.NORMAL); hotel.enter(new Customer("森田", 4000), Hotel.RoomRank.ECONOMY); System.out.println(); // ホテルを運営 hotel.manage(); System.out.println(); // お客様情報の確認 hotel.showCustomerInfo(); System.out.println(); // ホテル情報の確認 hotel.showHotelInfo(); } } // ここにホテルクラスを作成してください // 人抽象クラス abstract class Person { // 氏名 protected String name; // 名前取得メソッド public String getName() { return name; } } // 労働可能インタフェース interface Workable { // 働く抽象メソッド void work(); } // ここに従業員クラスを作成してください // ここに顧客クラスを作成してください // 所持金不足例外クラス class ShortFallException extends Exception { public ShortFallException(String message) { super(message); } }
参考図書
独学で挫折しそうになったら、オンラインプログラミングスクール