Java マスター講座:基礎から応用まで(授業資料)

本授業は、Javaプログラミングの基礎から応用までを体系的に学習する全17回の演習科目である。JavaTutor、Paiza.IO、OnlineGDBを演習環境として使用し、各回で理論説明と実践演習を組み合わせた構成となっている。

カリキュラム構成

本授業は以下の4つの部で構成される。

  1. 第1部:プログラミング基礎(pi-1〜pi-6)

    プログラミングの基本概念から始まり、変数、データ型、メソッド、条件分岐、コレクション、繰り返しを習得する。

  2. 第2部:オブジェクト指向プログラミング(pi-7〜pi-11)

    クラス、メソッド、コンストラクタ、継承、ジェネリクス、多相性、インターフェイス、デザインパターンを学ぶ。

  3. 第3部:応用技術(pi-12〜pi-14)

    時間処理、疑似乱数、タイマー、イベント処理、ソケット通信を学習する。

  4. 第4部:設計と品質(pi-15〜pi-17)

    カプセル化、MVCモデル、テスト、例外処理、プログラム設計を学び、ソフトウェア開発の実践力を養う。

学習内容一覧

タイトル 主要な学習内容
pi-1 プログラミング入門 プログラミングの基本概念
pi-2 Java プログラミングの基本 変数、データ型、基本構文
pi-3 式の抽象化とメソッド メソッドの定義と呼び出し
pi-4 条件分岐, ステップ実行 if文、デバッグ手法
pi-5 コレクション,リスト,マップ データ構造の基礎
pi-6 繰り返し(ループ) for文、while文
pi-7 クラス,メソッド,オブジェクト生成(コンストラクタ) クラス定義、コンストラクタ
pi-8 クラス設計 オブジェクト指向設計の基礎
pi-9 スーパークラス,サブクラス,継承 継承、クラス階層
pi-10 コレクション,ジェネリクス 型パラメータ、汎用コレクション
pi-11 多相性,インターフェイス,デザインパターン ポリモーフィズム、設計パターン
pi-12 時間,スリープ,疑似乱数,タイマー 時間処理、乱数生成
pi-13 今までの総まとめ 基礎〜応用の統合演習
pi-14 イベント,イベントハンドラ,ソケット通信 イベント駆動、ネットワーク通信
pi-15 カプセル化,MVCモデル,オブジェクトのマッピング 情報隠蔽、アーキテクチャパターン
pi-16 プログラムのテスト,アサーション,例外処理 テスト手法、エラー処理
pi-17 プログラム設計 設計手法、開発プロセス

到達目標

本授業を修了した受講者は、Javaを用いたプログラム作成ができるようになる。また、オブジェクト指向プログラミングの概念を理解し、クラス設計、継承、多相性を活用したソフトウェア開発ができるようになる。

授業の特徴

本授業は、JavaTutor、Paiza.IO、OnlineGDBによるオンライン演習環境を活用し、理論と実践の両面からJavaプログラミングを習得できる構成となっている。基礎的な文法、オブジェクト指向、MVCモデル、デザインパターンを扱う。実践的なソフトウェア開発能力を養成する。

【関連する外部ページ】

教材の利用条件: クリエイティブコモンズ 表示-非営利-継承 4.0 国際ライセンス(CC BY-NC-SA 4.0)に基づき、著作者表示・非営利目的・同一ライセンスでの再配布を条件として自由に利用可能である。

1. プログラミング入門

資料:pi-1. プログラミング入門 [PDF], [パワーポイント]

演習パート(クリックして展開)

Java Tutor の基本操作

Java Tutorは、Javaなどのプログラミング言語を体験・演習できるオンラインサービスである。

  1. ウェブブラウザを起動する
  2. 次のURLを開く:https://pythontutor.com/java.html
  3. 編集画面が開く(「Java」と表示されていることを確認する)

編集画面は以下の要素で構成される。

プログラム実行手順

  1. 「Visualize Execution」をクリックして実行画面に切り替える
  2. 「Last」をクリックする
  3. 実行結果を確認する
  4. 「Edit this code」をクリックして編集画面に戻る

使用上の注意

課題1

  1. Java Tutorのエディタで、以下のプログラムを入力する
    public class YourClassNameHere {
        public static void main(String[] args) {
            System.out.println(1.0/3.0);
        }
    }
            
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認し、表示された値を記録する
  5. 「Edit this code」をクリックして編集画面に戻る

課題2

  1. Java Tutorのエディタで、以下のプログラムを入力する
    public class YourClassNameHere {
        public static void main(String[] args) {
            System.out.println(6 * 1.1);
        }
    }
            
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認し、表示された値を記録する
  5. 「Edit this code」をクリックして編集画面に戻る

課題3

  1. Java Tutorのエディタで、以下のプログラムを入力する
    public class YourClassNameHere {
        public static void main(String[] args) {
            System.out.println(3 * 1.1);
        }
    }
            
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認し、表示された値を記録する
  5. 「Edit this code」をクリックして編集画面に戻る

考察のポイント

以下の点について考察すること。

補足:GDB online での実行

GDB onlineは、Javaプログラムの実行に使用できる別のオンラインサービスである。

使用手順

  1. ウェブブラウザを起動する
  2. 次のURLを開く:https://www.onlinegdb.com
  3. 「Language」で「Java」を選ぶ
  4. エディタにソースコードを入力する
  5. 「Run」をクリックして実行する
  6. 実行結果を確認する

2. Java プログラミングの基本

資料:pi-2. Java プログラミングの基本 [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

Javaのデータの種類

演習では整数型(int)と文字列型(String)を使用する。以下にJavaの主なデータの種類を示す。

基本データ型

分類型名サイズ
整数byte8 bit
short16 bit
int32 bit
long64 bit
浮動小数float32 bit
double64 bit
文字char16 bit
真偽値boolean-

その他

演習1:整数型変数の宣言と代入

整数型(int)の変数を宣言し、値を代入する方法を理解する。

用語

手順

  1. Java Tutorの編集画面を開く
  2. 以下のプログラムを入力する:
    public class YourClassNameHere {
        public static void main(String[] args) {
            int x = 100;
        }
    }
    
  3. 「Visualize Execution」をクリックする
  4. 「Last」をクリックする
  5. 画面右側に変数xとその値が表示されていることを確認する
  6. 「Edit this code」をクリックして編集画面に戻る

ヒント

演習2:文字列型変数の宣言と代入

文字列型(String)の変数を宣言し、文字列を代入する方法を理解する。

手順

  1. Java Tutorの編集画面を開く
  2. 以下のプログラムを入力する:
    public class YourClassNameHere {
        public static void main(String[] args) {
            String s = "abc";
        }
    }
    
  3. 「Visualize Execution」をクリックする
  4. 「Last」をクリックする
  5. 画面右側に変数sとその値が表示されていることを確認する
  6. 「Edit this code」をクリックして編集画面に戻る

ヒント

3. 式の抽象化とメソッド

資料:pi-3. 式の抽象化とメソッド [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1-1:変数を使った加算

整数型の変数を宣言し、加算の結果を確認する。

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
public class YourClassNameHere {
  public static void main(String[] args) {
    int x = 100;
    int y = 200;
    System.out.println(x + y);
  }
}
  1. 「Visualize Execution」をクリックする
  2. 「Last」をクリックする
  3. 出力結果を確認する
  4. 「Edit this code」をクリックして編集画面に戻る

ヒント

代入とは、「x = 100」のように書くことで変数xの値を100に設定する操作である。int型(整数型)は整数を扱うデータ型である。System.out.println()は、括弧内の値を画面に出力する命令である。

演習1-2:変数を使った乗算

乗算演算子を使った式の結果を確認する。

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
public class YourClassNameHere {
  public static void main(String[] args) {
    int x = 100;
    int y = 200;
    System.out.println(x * y);
  }
}
  1. 「Visualize Execution」をクリックする
  2. 「Last」をクリックする
  3. 出力結果を確認する
  4. 「Edit this code」をクリックして編集画面に戻る

ヒント

Javaでは乗算に「*」記号を使用する。演習1-1のプログラムとの違いは演算子のみである。式が異なれば、実行結果も異なることを確認すること。

演習1-3:複合式の計算

括弧を含む式の評価順序を理解する。

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
public class YourClassNameHere {
  public static void main(String[] args) {
    int x = 100;
    int y = 200;
    System.out.println((x + 10) * y);
  }
}
  1. 「Visualize Execution」をクリックする
  2. 「Last」をクリックする
  3. 出力結果を確認する
  4. 「Edit this code」をクリックして編集画面に戻る

ヒント

括弧内の式が先に評価される。このプログラムでは、(x + 10)が先に計算され、その結果にyを掛ける。数学と同じ優先順位の規則が適用される。

演習1-4:三角形の面積計算

小数を扱うデータ型を使った計算を実行する。

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
public class YourClassNameHere {
  public static void main(String[] args) {
    double teihen = 2.5;
    double takasa = 5;
    System.out.println(teihen * takasa / 2);
  }
}
  1. 「Visualize Execution」をクリックする
  2. 「Last」をクリックする
  3. 出力結果を確認する
  4. 「Edit this code」をクリックして編集画面に戻る

ヒント

三角形の面積は「底辺 × 高さ ÷ 2」で計算する。double型(浮動小数点型)はint型と異なり小数を扱える。変数名にはローマ字も使用できる。

演習2-1:メソッドによる式の抽象化

類似した複数の式を変数で1つにまとめる「抽象化」と、メソッドの定義・使用方法を理解する。

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する(第3章でも使用するため消さないこと)
public class YourClassNameHere {
  public static double foo(double a) {
    return a * 1.1;
  }
  public static void main(String[] args) {
    System.out.println(foo(100));
    System.out.println(foo(150));
    System.out.println(foo(400));
  }
}
  1. 「Visualize Execution」をクリックする
  2. 「Last」をクリックする
  3. 3行の出力結果を確認する
  4. 「Edit this code」をクリックして編集画面に戻る(プログラムは消さないこと)

ヒント

100 * 1.1、150 * 1.1、400 * 1.1という類似した式を、変数aを使って「a * 1.1」という1つの式にまとめている。これが抽象化である。メソッド(オブジェクトに属する操作や処理)fooは、式「a * 1.1」に名前fooを付けたものと考えることができる。引数(ひきすう)とは、メソッドに渡す値のことである。returnは、メソッドの計算結果を呼び出し元に返す命令である。

演習3-1:ステップ実行の準備

メソッド呼び出しの動作を観察するため、ステップ実行の準備をする。

手順

  1. 演習2-1のプログラムが編集画面にあることを確認する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックして実行結果を確認する
  4. 「First」をクリックして最初に戻る

ヒント

「First」ボタンでプログラムの実行状態を最初に戻すことができる。ステップ実行(プログラムを1ステップずつ実行して動作を観察する機能)の準備として、まず最初の状態に戻す。

演習3-2:ステップ数と初期状態の確認

プログラム全体のステップ数と、実行開始前の状態を確認する。

手順

  1. 画面に表示されている「Step 1 of 17」を確認する
  2. 画面右側のオブジェクト表示領域を確認する
  3. 赤い矢印がmainメソッドの先頭を指していることを確認する

ヒント

このプログラムは全部で17ステップある。ステップ数とプログラムの行数は異なる。赤い矢印は「次に実行される行」を示す。プログラム開始時点では変数はまだ生成されていない。

演習3-3:メソッド間のジャンプの観察

メソッド呼び出し時に実行位置がmainメソッドとfooメソッドの間で移動する様子を観察する。

手順

  1. 「Next」ボタンを繰り返しクリックする
  2. 赤い矢印の動きを観察し、mainとfooの間で移動することを確認する
  3. 「Next」ボタンを押しても進めなくなったら実行終了である
  4. 「First」をクリックして最初に戻る

ヒント

foo(100)が呼び出されると、実行位置がmainメソッドからfooメソッドへ移動する。fooメソッドの処理が終わると、mainメソッドの次の行に戻る。foo(150)、foo(400)でも同様の動作が発生する。

演習3-4:変数の生成と消去の観察

メソッド内の変数が生成・消去されるタイミングを理解する。

手順

  1. 「Next」ボタンを繰り返しクリックする
  2. 緑の矢印と画面右側の変数表示を観察する
  3. fooメソッドの実行中に変数aが現れることを確認する
  4. fooメソッドからmainメソッドに戻ると変数aが消えることを確認する

ヒント

緑の矢印は「いま実行が終わった行」を示す。メソッド呼び出しでは、実行位置の移動だけでなく変数の生成と消去が自動で行われる。fooメソッドの引数aは、fooメソッドの実行中のみ存在し、処理終了後に自動的に消去される。

全体のまとめ

4. 条件分岐, ステップ実行

資料:pi-4. 条件分岐, ステップ実行 [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:条件分岐の実行(age=10)

条件式が真のとき、if節が実行されることを確認する。

手順

  1. 以下のプログラムを入力する:
    public class YourClassNameHere {
        public static void main(String[] args) {
            int age = 10;
            if (age <= 12) {
                System.out.println("500 yen");
            } else {
                System.out.println("1200 yen");
            }
        }
    }
    
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 「500 yen」と表示されることを確認する
  5. 「Edit this code」をクリックして編集画面に戻る

ヒント

条件式「age <= 12」は「ageが12以下」を意味する。age=10は12以下であるため、条件式は真となる。

演習2:条件分岐の実行(age=20)

目的

条件式が偽のとき、else節が実行されることを確認する。

手順

  1. 「int age = 10;」を「int age = 20;」に変更する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 「1200 yen」と表示されることを確認する
  5. 「Edit this code」をクリックして編集画面に戻る
  6. プログラムは残しておく(次の演習で使用)

ヒント

age=20は12以下ではないため、条件式は偽となり、else節が実行される。

演習3:ステップ実行の観察(else節が実行される場合)

目的

ステップ実行で、条件式が偽のときのジャンプを観察する。

手順

  1. 演習2のプログラム(age=20)が入力されていることを確認する
  2. 「Visualize Execution」をクリックする
  3. 「Step 1 of 5」と表示されることを確認する
  4. 「Next」を繰り返しクリックし、矢印の動きを観察する
  5. 4行目から7行目へジャンプする様子に注目する
  6. 「Edit this code」をクリックして編集画面に戻る

ヒント

プログラムは通常、上から順に実行される(逐次実行)。条件分岐では、条件式が偽のときif節をスキップしてelse節へジャンプする。

演習4:ステップ実行の観察(if節が実行される場合)

目的

ステップ実行で、条件式が真のときのジャンプを観察する。

手順

  1. 「int age = 20;」を「int age = 10;」に変更する
  2. 「Visualize Execution」をクリックする
  3. 「Next」を繰り返しクリックし、矢印の動きを観察する
  4. 5行目から9行目へジャンプする様子に注目する
  5. 演習3との違いを確認する

ヒント

条件式が真のとき、if節が実行され、else節はスキップされる。演習3と比較し、ジャンプ先の違いを確認せよ。

演習5:条件分岐プログラムの作成

条件分岐の知識を応用し、新しいプログラムを作成する。

課題

以下の仕様を満たすプログラムを作成せよ。

手順

  1. 演習1のプログラム構造を参考にプログラムを作成する
  2. weight=50でテスト実行し、「0 yen」が出力されることを確認する
  3. weight=100、weight=150などでも正しく動作することを確認する

ヒント

変更箇所は、変数名、条件式、出力メッセージの3点である。「100未満」は比較演算子「<」で表現する。

まとめ

5. コレクション,リスト,マップ

資料:pi-5. コレクション,リスト,マップ [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

リストとは

リストは、同じ型の要素を順序付けて格納するデータ構造である。 要素には0から始まる番号(添字)が付いており、要素の削除や挿入によりサイズが増減する。

例:要素 [15, 8, 6, 32, 23] を持つリストでは、添字0に15、添字1に8、添字2に6が格納されている。

演習1:リストの生成と要素の挿入

ArrayListクラスを使用して空のリストを生成し、addメソッドで要素を挿入する方法を学ぶ。

以下のプログラムをJava Tutorのエディタに入力し、実行する。

import java.util.ArrayList;

public class YourClassNameHere {
    public static void main(String[] args) {
        ArrayList<String> m = new ArrayList<String>();
        m.add("15");
        m.add("8");
        m.add("6");
        m.add("32");
        m.add("23");
    }
}

オブジェクトmが生成されていることを確認する。 Java Tutorにはコレクションの要素を表示する機能がないため、この演習ではオブジェクトの生成のみを確認する。

プログラムは以降の演習でも使用するため、消さずに残しておくこと。

補足

演習2:リストのサイズ取得

sizeメソッドを使用してリストの要素数を取得する方法を学ぶ。

演習1のプログラムを以下のように修正し、実行する。

import java.util.ArrayList;

public class YourClassNameHere {
    public static void main(String[] args) {
        ArrayList<String> m = new ArrayList<String>();
        m.add("15");
        m.add("8");
        m.add("6");
        m.add("32");
        m.add("23");
        System.out.println(m.size());
    }
}

出力結果が「5」であることを確認する。

補足

演習3:リストの検索

indexOfメソッドを使用してリスト内の要素を検索し、その添字を取得する方法を学ぶ。

演習2のプログラムを以下のように修正し、実行する。

import java.util.ArrayList;

public class YourClassNameHere {
    public static void main(String[] args) {
        ArrayList<String> m = new ArrayList<String>();
        m.add("15");
        m.add("8");
        m.add("6");
        m.add("32");
        m.add("23");
        System.out.println(m.indexOf("6"));
    }
}

出力結果が「2」であることを確認する。 なぜ「2」になるのか考えること。

補足

ArrayListクラスの主なメソッド

演習4:VisualGoでのリスト操作

VisualGoを使用して、リストへの要素挿入を視覚的に体験する。

以下の手順で操作する。

  1. ウェブブラウザでURL「https://visualgo.net/ja」を開く
  2. 「Linked List (連結リスト)」をクリックする
  3. 説明が表示された場合はESCキーで閉じる
  4. 左下のメニューで「Enqueue (入れる)」をクリックする
  5. 「Go」をクリックする
  6. 末尾に要素が挿入されるアニメーションを確認する

補足

マップとは

マップは、キーと値(バリュー)のペアを格納するデータ構造である。 同じキーは2回以上登場しない(キーは一意である)。

例:キー1に値"Red"、キー2に値"Yellow"、キー3に値"Blue"を持つマップでは、キー2を指定すると値"Yellow"を取得できる。

演習5:マップの生成と要素の挿入

HashMapクラスを使用して空のマップを生成し、putメソッドでキーと値のペアを挿入する方法を学ぶ。

以下のプログラムをJava Tutorのエディタに入力し、実行する。

import java.util.HashMap;

public class YourClassNameHere {
    public static void main(String[] args) {
        HashMap<Integer, String> x = new HashMap<Integer, String>();
        x.put(1, "Red");
        x.put(2, "Yellow");
        x.put(3, "Blue");
        System.out.println(x.size());
    }
}

出力結果が「3」であることを確認する。

補足

演習6:マップの検索

getメソッドを使用してキーから値を取得する方法を学ぶ。

演習5のプログラムを以下のように修正し、実行する。

import java.util.HashMap;

public class YourClassNameHere {
    public static void main(String[] args) {
        HashMap<Integer, String> x = new HashMap<Integer, String>();
        x.put(1, "Red");
        x.put(2, "Yellow");
        x.put(3, "Blue");
        System.out.println(x.get(2));
    }
}

出力結果が「Yellow」であることを確認する。 getメソッドの引数を1や3に変更して、結果がどう変わるか確認すること。

補足

HashMapクラスの主なメソッド

まとめ

複数のデータを扱う場合、コレクションを使用すると検索、挿入、削除を効率的に行える。

6. 繰り返し(ループ)

資料:pi-6. 繰り返し(ループ) [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:配列の基本操作

配列(同じ型のデータの並びで、0から始まる番号である添字が付いたもの)を作成し、特定の要素にアクセスする方法を学ぶ。

手順

  1. Java Tutorのエディタを開く
  2. 以下のプログラムを入力する。このプログラムは各月の日数を格納した配列を作成し、9月の日数を表示する
    public class YourClassNameHere {
        public static void main(String[] args) {
            int days[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
            System.out.println(days[9]);
        }
    }
    
  3. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  4. 表示された値が9月の日数として正しいか確認する

ヒント

演習2:配列と繰り返し

この演習は3つのパートで構成される。配列とfor文を組み合わせた処理を段階的に学ぶ。

for文(変数の値を変化させながら処理を繰り返す構文)を使用し、配列の全要素に対して同じ処理を行う方法を学ぶ。

演習2-a:配列の全要素を表示する

手順

  1. Java Tutorのエディタで以下のプログラムを入力する
    public class YourClassNameHere {
        public static void main(String[] args) {
            double x[] = {10, 20, 30, 40};
            int i;
            for(i = 0; i <= 3; i++) {
                System.out.println(x[i]);
            }
        }
    }
    
  2. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  3. 配列の4つの要素が順番に表示されることを確認する

ヒント

演習2-b:物体の落下距離を計算する

手順

  1. Java Tutorのエディタで以下のプログラムを入力する。物体の落下距離は 9.8 × 時間2 ÷ 2 で計算する
    public class YourClassNameHere {
        public static void main(String[] args) {
            double x[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
            int i;
            for(i = 0; i <= 10; i++) {
                System.out.println((9.8 / 2) * x[i] * x[i]);
            }
        }
    }
    
  2. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  3. 0秒から10秒までの各時刻における落下距離が表示されることを確認する

ヒント

演習2-c:配列要素の計算結果を別配列に格納する

手順

  1. Java Tutorのエディタで以下のプログラムを入力する
    public class YourClassNameHere {
        public static void main(String[] args) {
            double x[] = {8, 6, 4, 2, 3};
            double y[] = {0, 0, 0, 0, 0};
            int i;
            for(i = 0; i <= 4; i++) {
                y[i] = x[i] * 1.1;
            }
        }
    }
    
  2. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  3. 配列yに、配列xの各要素の1.1倍の値が格納されていることを確認する
  4. このプログラムは次の演習3で使用するため、消さずに残しておく

ヒント

演習3:ステップ実行

ステップ実行機能を使用し、プログラムが1行ずつ実行される様子と変数の値の変化を確認する方法を学ぶ。

手順

  1. 演習2-cで入力したプログラムがJava Tutorに残っていることを確認する
  2. 「Visualize Execution」をクリックする
  3. 画面に「Step 1 of 21」のように表示される。これは全体で21ステップあることを示している。ステップ数とプログラムの行数は異なる
  4. 「Next」ボタンをクリックして、1ステップずつ実行を進める
  5. 矢印が示す実行中の行と、右側に表示される変数の値の変化を観察する
  6. for文の繰り返し部分が複数回実行される様子を確認する
  7. 配列yの中身が徐々に更新されていく様子を確認する
  8. 「Next」ボタンを押してもそれ以上進めなくなったら終了である

ヒント

演習4:リストと拡張for文

ArrayList(要素の追加・削除によりサイズが変化するリスト)と拡張for文(コレクション(リストやマップなどのデータの集まり)の要素を順にたどるための構文)の使い方を学ぶ。

手順

  1. Java Tutorのエディタで以下のプログラムを入力する
    import java.util.ArrayList;
    
    public class YourClassNameHere {
        public static void main(String[] args) {
            ArrayList<String> m = new ArrayList<String>();
            m.add("15");
            m.add("8");
            m.add("6");
            m.add("32");
            m.add("23");
            for(String s: m) {
                System.out.println(s);
            }
        }
    }
    
  2. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  3. リストに追加した5つの要素が順番に表示されることを確認する

ヒント

まとめ

7. クラス,メソッド,オブジェクト生成(コンストラクタ)

資料:pi-7. クラス,メソッド,オブジェクト生成(コンストラクタ) [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:クラス定義、オブジェクト生成、メソッドアクセス

クラス定義、newによるオブジェクト生成、メソッドアクセスの基本を学ぶ。

背景知識

クラスは、同じ種類のオブジェクトの集まりと考えることができる。例えば「Ball」というクラスを定義すると、半径、場所、色などの属性を持つ複数のボールオブジェクトを作成できる。オブジェクトを生成するには、コンストラクタ(オブジェクト生成のためのメソッド)をnewキーワードとともに使用する。コンストラクタはクラス名と同じ名前を持つ。

手順

  1. Java Tutorのエディタを開く
  2. 以下のプログラムを入力する
class Ball {
    double x;
    double y;
    double r;
    String color;
    public Ball(double x, double y, double r, String color) {
        this.x = x;
        this.y = y;
        this.r = r;
        this.color = color;
    }
    public void printout() {
        System.out.println(this.x);
        System.out.println(this.y);
        System.out.println(this.r);
        System.out.println(this.color);
    }
}

public class YourClassNameHere {
    public static void main(String[] args) {
        Ball a = new Ball(8, 10, 1, "blue");
        Ball b = new Ball(2, 4, 3, "green");
        a.printout();
        b.printout();
    }
}
  1. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  2. printoutメソッドによる表示と、オブジェクトa、bの内容を確認する
  3. 「First」をクリックしてプログラム実行を先頭に戻す
  4. 「Step 1 of 38」と表示されていることを確認する。ステップ数は38である
  5. 「Next」ボタンを繰り返しクリックし、ステップ実行でプログラムの流れを確認する
  6. プログラムは次の演習で使用するため、消さずに残しておく

ヒント

演習2:thisによる属性アクセス

thisキーワードを使った属性アクセスを学ぶ。

背景知識

メソッドや属性はクラスに属する。メソッド定義内で、そのメソッドが所属するクラスで定義された属性やメソッドにアクセスするときはthis+「.」を使用する。メソッド外ではオブジェクト名+「.」を使用する。

手順

  1. 演習1のプログラムを開く
  2. Ballクラス内のprintoutメソッドの後に、以下のdistメソッドを追加する
    public double dist() {
        return this.x + this.y;
    }
  1. mainメソッド内のb.printout();の後に、以下の1行を追加する
        System.out.println(a.dist());
  1. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  2. distメソッドの戻り値が表示されていることを確認する
  3. プログラムは次の演習で使用するため、消さずに残しておく

ヒント

演習3:moveメソッドの定義

オブジェクトの属性を変更するメソッドを定義する。

背景知識

オブジェクトの位置を移動させることを考える。上下左右の移動は、属性xとyを増減することで実現できる。

手順

  1. 演習2のプログラムを開く
  2. Ballクラス内のdistメソッドの後に、以下のmoveメソッドを追加する
    public void move(double xx, double yy) {
        this.x = this.x + xx;
        this.y = this.y + yy;
    }
  1. mainメソッド内のオブジェクト生成の後、printoutの前に、以下の2行を追加する
        a.move(5, 5);
        b.move(10, 10);
  1. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する
  2. オブジェクトaとbの位置がmoveメソッドによって変更されていることを確認する
  3. プログラムは次の演習で使用するため、消さずに残しておく

ヒント

演習4:right/leftメソッドの定義と応用

既存のメソッドを再利用して新しいメソッドを定義する。

課題

  1. 右に動かすためのメソッドrightを定義する
  2. 左に動かすためのメソッドleftを定義する
  3. rightを使って、オブジェクトaを右に5動かす
  4. leftを使って、オブジェクトbを左に10動かす

手順

  1. 演習3のプログラムを開く
  2. Ballクラス内のmoveメソッドの後に、rightメソッドとleftメソッドを追加する
  3. mainメソッド内で、rightメソッドとleftメソッドを呼び出すコードを追加する
  4. 「Visualize Execution」をクリックし、「Last」をクリックして実行結果を確認する

ヒント

ヒント

まとめ

8. クラス設計

資料:pi-8. クラス設計 [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:クラス定義とオブジェクト生成(設計例①)

クラス定義の基本構造を理解し、コンストラクタ(オブジェクト生成時に実行される初期化処理)によるオブジェクト生成の方法を学ぶ。また、文字列を直接指定する方式の問題点を認識する。

手順

  1. 以下のプログラムをJava Tutorに入力し、実行する
  2. オブジェクトsが生成され、colorに"red"が設定されていることを確認する
  3. プログラム中の"red"を"rrd"に書き換えて再度実行する
  4. 書き間違いがあっても実行できてしまうことを確認する
class Signal {
    String color;
    public Signal(String color) {
        this.color = color;
    }
}

public class YourClassNameHere {
    public static void main(String [] args) {
        Signal s = new Signal("red");
    }
}

ヒント

演習2:クラス設計(設計例②)

演習1では、コンストラクタに任意の文字列を渡せるため、不正なデータが混入する可能性があった。この演習では、その問題を解決する別の設計方式を学ぶ。

不正なデータの混入を防ぐクラス設計を学ぶ。コンストラクタで値を設定する代わりに、専用のメソッドを用意する方式を理解する。

手順

  1. 以下のプログラムをJava Tutorに入力し、実行する
  2. オブジェクトsが生成され、s.red()の呼び出しによりcolorに"red"が設定されていることを確認する
  3. 演習1の方式と比較し、この方式ではタイプミスによる不正なデータ混入が防げる理由を考える
class Signal {
    String color;
    public Signal() {};
    public void red() { this.color = "red"; };
    public void yellow() { this.color = "yellow"; };
    public void blue() { this.color = "blue"; };
}

public class YourClassNameHere {
    public static void main(String [] args) {
        Signal s = new Signal();
        s.red();
    }
}

ヒント

演習3:オブジェクトの状態変化(Signal)

演習2で作成したSignalクラスを拡張し、信号の状態が自動的に変化するメソッドを追加する。

オブジェクトの属性を「状態」として捉え、メソッドによる「状態変化」を実装する方法を学ぶ。

手順

  1. 以下のプログラムをJava Tutorに入力し、実行する
  2. s.red()でcolorが"red"に設定された後、s.go()でcolorが"blue"に変化することを確認する
  3. goメソッドの動作を追跡し、状態変化の規則を理解する
class Signal {
    String color;
    public Signal() {};
    public void red() { this.color = "red"; };
    public void yellow() { this.color = "yellow"; };
    public void blue() { this.color = "blue"; };
    public void go() {
        if (this.color.equals("blue")) { this.yellow(); }
        else if (this.color.equals("yellow")) { this.red(); }
        else if (this.color.equals("red")) { this.blue(); }
    }
}

public class YourClassNameHere {
    public static void main(String [] args) {
        Signal s = new Signal();
        s.red();
        s.go();
    }
}

ヒント

演習4:オブジェクトの状態と状態変化(Product)

演習3で学んだ状態変化のパターンを、別の例に適用する。

製品のアクティブ/非アクティブ状態を管理するクラスを通じて、状態変化パターンの応用を学ぶ。

手順

  1. 以下のプログラムをJava Tutorに入力し、実行する
  2. p.deactive()でsが"deactive"に設定された後、p.on()でsが"active"に変化することを確認する
  3. onメソッドとoffメソッドの条件分岐の役割を理解する
class Product {
    String s;
    public Product() {};
    public void active() { this.s = "active"; };
    public void deactive() { this.s = "deactive"; };
    public void on() {
        if (this.s.equals("deactive")) { this.active(); }
    }
    public void off() {
        if (this.s.equals("active")) { this.deactive(); }
    }
}

public class YourClassNameHere {
    public static void main(String [] args) {
        Product p = new Product();
        p.deactive();
        p.on();
    }
}

ヒント

演習5:メソッド内でのみ使用する変数

ここからは、クラス設計とは別の話題として、変数のスコープについて学ぶ。

メソッド内で宣言された変数(ローカル変数)のスコープ(有効範囲)を理解する。メソッドの実行終了とともに変数が自動で消えることを確認する。

手順

  1. 以下のプログラムをJava Tutorに入力する
  2. 「Visualize Execution」をクリックし、「Next」を繰り返しクリックして、変数の生成と消滅を追跡する
  3. 実行画面の「Frames」欄を観察し、メソッド呼び出し時に新しいフレームが作成され、メソッド終了時に消えることを確認する
  4. fooメソッド内の変数aと、mainメソッド内の変数pが、それぞれのメソッド内でのみ存在することを確認する
public class YourClassNameHere {
    public static double foo(double a) {
        return a * 1.1;
    }
    public static void main(String [] args) {
        double p;
        p = 120;
        System.out.printf("%f¥n", foo(p));
        p = 200;
        System.out.printf("%f¥n", foo(p));
    }
}

ヒント

演習6:抽象化の組み合わせ

類似した複数の式を変数とメソッドで抽象化する手法を学ぶ。抽象化を組み合わせることで、より汎用的なコードを作成する方法を理解する。

手順

  1. 以下のプログラムをJava Tutorに入力し、実行する
  2. y(5)、y(12)、z(8)、z(16)の計算結果を確認する
  3. メソッドx、y、zの関係を分析し、どのように抽象化が組み合わされているかを考える
public class YourClassNameHere {
    public static double x(double a) {
        return a * 1.1;
    }
    public static double y(double b) {
        return x(b * 100);
    }
    public static double z(double c) {
        return x(c * 200);
    }
    public static void main(String [] args) {
        System.out.printf("%f¥n", y(5));
        System.out.printf("%f¥n", y(12));
        System.out.printf("%f¥n", z(8));
        System.out.printf("%f¥n", z(16));
    }
}

ヒント

まとめ

クラス設計と状態変化は、オブジェクト指向プログラミングの基礎となる考え方である。変数のスコープと抽象化は、プログラムの構造を整理し、保守しやすいコードを書くための基本技術である。

9. スーパークラス,サブクラス,継承

資料:pi-9. スーパークラス,サブクラス,継承 [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

クラスとオブジェクト

クラスは、同じ種類のオブジェクトの集まりである。「人間」クラスと「学生」クラスがある場合、学生は人間でもある。

スーパークラスとサブクラス

サブクラスのオブジェクトは、すべてスーパークラスに属する。「長方形」と「正方形」の関係では、正方形は必ず長方形であるため、長方形がスーパークラス、正方形がサブクラスとなる。

継承

継承とは、スーパークラスの属性とメソッドをサブクラスが受け継ぐ仕組みである。ただし、コンストラクタは受け継がない。

演習1:継承の基本

extendsによるスーパークラスの指定と、superによるスーパークラスのコンストラクタ呼び出しを理解する。

手順

  1. Java Tutorの編集画面を開く
  2. 以下のRectangleクラスを入力する
    class Rectangle {
        double x;
        double y;
        double width;
        double height;
        public Rectangle(double x, double y, double width, double height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }
        public void printout() {
            System.out.println(this.x);
            System.out.println(this.y);
            System.out.println(this.width);
            System.out.println(this.height);
        }
    }
    
  3. 続けて、以下のSquareクラスを入力する
    class Square extends Rectangle {
        public Square(double x, double y, double size) {
            super(x, y, size, size);
        }
    }
    
  4. 続けて、以下のmainメソッドを入力する
    public class YourClassNameHere {
        public static void main(String[] args) {
            Rectangle a = new Rectangle(4, 8, 1, 2);
            Rectangle b = new Rectangle(8, 10, 2, 1);
            a.printout();
            b.printout();
            Square c = new Square(0, 3, 1);
            Square d = new Square(1, 1, 2);
            c.printout();
            d.printout();
        }
    }
    
  5. 「Visualize Execution」をクリックし、「Last」をクリックして結果を確認する
  6. プログラムを消さずに次の演習に進む

ヒント

確認ポイント

演習2:メソッドのオーバーライド

メソッドのオーバーライドを理解する。オーバーライドとは、サブクラスでスーパークラスのメソッドを別の定義に置き換えることである。

手順

  1. 演習1のプログラムを使用する(プログラムを消さないこと)
  2. Squareクラスを以下のように変更し、printoutメソッドを追加する
    class Square extends Rectangle {
        public Square(double x, double y, double size) {
            super(x, y, size, size);
        }
        public void printout() {
            System.out.println(this.x);
            System.out.println(this.y);
            System.out.println(this.width);
        }
    }
    
  3. 「Visualize Execution」をクリックし、「Last」をクリックして結果を確認する
  4. プログラムを消さずに次の演習に進む

ヒント

確認ポイント

演習3:サブクラスでの属性の追加

目的

サブクラスでスーパークラスにない属性やメソッドを追加できることを理解する。

手順

  1. 演習2のプログラムを使用する(プログラムを消さないこと)
  2. Squareクラスの後に、以下のColorRectangleクラスを追加する
    class ColorRectangle extends Rectangle {
        String color;
        public ColorRectangle(double x, double y, double width, double height, String color) {
            super(x, y, width, height);
            this.color = color;
        }
        public void printout() {
            System.out.println(this.x);
            System.out.println(this.y);
            System.out.println(this.width);
            System.out.println(this.height);
            System.out.println(this.color);
        }
    }
    
  3. mainメソッドの末尾(d.printout();の後)に、以下のコードを追加する
            ColorRectangle e = new ColorRectangle(0, 0, 1, 4, "Red");
            e.printout();
    
  4. 「Visualize Execution」をクリックし、「Last」をクリックして結果を確認する

ヒント

確認ポイント

まとめ

キーワード一覧

用語説明
スーパークラス継承関係において、属性とメソッドを継承されるクラス
サブクラス継承関係において、属性とメソッドを継承するクラス
継承スーパークラスの属性とメソッドをサブクラスが受け継ぐ仕組み
extendsスーパークラスを指定するキーワード
superスーパークラスのコンストラクタを呼び出すキーワード
オーバーライドサブクラスでスーパークラスのメソッドを別の定義に置き換えること

10. コレクション,ジェネリクス

資料:pi-10. コレクション,ジェネリクス [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:ArrayListの基本操作(String型)

ArrayListの基本的な使い方を理解する。要素の追加と拡張for文による走査を学ぶ。

前提知識

手順

  1. Java Tutorのエディタに以下のプログラムを入力する
  2. 実行し、15, 8, 6, 32, 23 が順番に表示されることを確認する
  3. 編集画面に戻る(プログラムは消さないこと)
import java.util.ArrayList;
import java.util.Iterator;

public class YourClassNameHere {
    public static void main(String[] args) {
        ArrayList<String> m = new ArrayList<String>();
        m.add("15");
        m.add("8");
        m.add("6");
        m.add("32");
        m.add("23");
        for(String s : m) {
            System.out.println(s);
        }
    }
}

ヒント

演習2:ArrayListの基本操作(Integer型)

Integer型を型変数に指定したArrayListの使い方を理解する。

前提知識

手順

  1. Java Tutorのエディタに以下のプログラムを入力する
  2. 実行し、100, 200, 300, 400, 500 が順番に表示されることを確認する
  3. 編集画面に戻る(プログラムは消さないこと)
import java.util.ArrayList;
import java.util.Iterator;

public class YourClassNameHere {
    public static void main(String[] args) {
        ArrayList<Integer> m = new ArrayList<Integer>();
        m.add(100);
        m.add(200);
        m.add(300);
        m.add(400);
        m.add(500);
        for(Integer s : m) {
            System.out.println(s);
        }
    }
}

ヒント

演習3:Object型を型変数に指定したリスト操作

異なるクラスのオブジェクトを同一のコレクションで扱う方法を理解する。

前提知識

手順

  1. Java Tutorのエディタに以下のプログラムを入力する
  2. 実行し、100, hello が順番に表示されることを確認する
  3. 編集画面に戻る
import java.util.ArrayList;
import java.util.Iterator;

public class YourClassNameHere {
    public static void main(String[] args) {
        ArrayList<Object> m = new ArrayList<Object>();
        m.add(100);
        m.add("hello");
        for(Object s : m) {
            System.out.println(s);
        }
    }
}

ヒント

演習4:ジェネリクスを用いたPairクラスの実装

ジェネリクスの仕組みを理解する。自作クラスに型パラメータを導入する方法を学ぶ。

前提知識

手順

  1. Java Tutorのエディタに以下のプログラムを入力する
  2. 実行し、1, 2, xx, yy が順番に表示されることを確認する
  3. Pair<Integer>とPair<String>が同じPairクラスから異なる型で生成されていることを確認する
class Pair<T> {
    T s;
    T e;
    public Pair(T s, T e) {
        this.s = s;
        this.e = e;
    }
    public void print() {
        System.out.println(s);
        System.out.println(e);
    }
}

public class YourClassNameHere {
    public static void main(String[] args) {
        Pair a = new Pair<Integer>(1, 2);
        Pair b = new Pair<String>("xx", "yy");
        a.print();
        b.print();
    }
}

ヒント

まとめ

11. 多相性,インターフェイス,デザインパターン

資料:pi-11. 多相性,インターフェイス,デザインパターン [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:クラス階層とメソッドのオーバーライド

スーパークラス(親クラス)とサブクラス(子クラス)によるクラス階層を理解し、メソッドのオーバーライド(同名メソッドをクラスごとに異なる内容で再定義すること)を実装する。

前提知識

クラス階層とは、共通する機能を持つ複数のクラスがある場合に、共通部分をスーパークラスにまとめ、個別の機能をサブクラスに定義する構造である。CircleクラスとRectangleクラスはいずれもFigureクラスのサブクラスであり、Figureクラスの機能を継承する。メソッドのオーバーライドにより、areaメソッドがクラスごとに異なる処理を行う。

手順

  1. 以下のプログラムをJava Tutorのエディタに入力する
  2. 「Java Tutorでのプログラム実行方法」に従って実行する
  3. CircleオブジェクトとRectangleオブジェクトそれぞれでareaメソッドが異なる計算結果を返すことを確認する
import java.util.ArrayList;

class Figure {
    double x;
    double y;
    String color;

    void move(double dx, double dy) {
        x = x + dx;
        y = y + dy;
    }

    double area() {
        return 0;
    }
}

class Circle extends Figure {
    double radius;

    double area() {
        return radius * radius * 3.14;
    }
}

class Rectangle extends Figure {
    double width;
    double height;

    double area() {
        return width * height;
    }
}

public class Main {
    public static void main(String[] args) {
        Circle c = new Circle();
        c.radius = 3;
        c.x = 2;
        c.y = 4;
        c.color = "green";

        Rectangle r = new Rectangle();
        r.width = 1;
        r.height = 2;
        r.x = 6;
        r.y = 4;
        r.color = "black";

        System.out.println(c.area());
        System.out.println(r.area());
    }
}

期待される出力

28.26
2.0

ヒント

演習2:多相性

多相性(異なるサブクラスのオブジェクトをスーパークラス型として統一的に扱う仕組み)を理解し、ArrayListを用いた実装を行う。

前提知識

この演習は演習1の発展である。多相性により、CircleオブジェクトもRectangleオブジェクトも「Figureクラスのオブジェクト」として扱える。ArrayList<Figure>に格納すると、各オブジェクトのareaメソッドを呼び出したとき、実際のクラスに応じた計算が行われる。

手順

  1. 以下のプログラムをJava Tutorのエディタに入力する
  2. 「Java Tutorでのプログラム実行方法」に従って実行する
  3. ArrayList<Figure>に格納されたCircleとRectangleがそれぞれ正しい面積を計算していることを確認する
import java.util.ArrayList;

class Figure {
    double x;
    double y;
    String color;

    void move(double dx, double dy) {
        x = x + dx;
        y = y + dy;
    }

    double area() {
        return 0;
    }
}

class Circle extends Figure {
    double radius;

    double area() {
        return radius * radius * 3.14;
    }
}

class Rectangle extends Figure {
    double width;
    double height;

    double area() {
        return width * height;
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Figure> figures = new ArrayList<Figure>();

        Circle x = new Circle();
        x.radius = 3;
        x.x = 2;
        x.y = 4;
        x.color = "green";
        figures.add(x);

        Rectangle a = new Rectangle();
        a.width = 1;
        a.height = 2;
        a.x = 6;
        a.y = 4;
        a.color = "black";
        figures.add(a);

        for (Figure f : figures) {
            System.out.println(f.area());
        }
    }
}

期待される出力

28.26
2.0

ヒント

演習3:インターフェイス

インターフェイス(クラスが特定のメソッドを実装していることを保証する仕組み)を理解し、継承関係のない複数のクラスで同名メソッドの実装を保証する方法を学ぶ。

前提知識

インターフェイスは、複数のクラスが同名のメソッドを持つことを保証する仕組みである。継承関係がないクラスでも、同じインターフェイスを実装することで、同一種類のオブジェクトとして扱える。インターフェイスに準拠しないクラス定義(必要なメソッドが未実装など)は、コンパイル時に警告が出る。

手順

  1. 以下のプログラムをJava Tutorのエディタに入力する
  2. 「Java Tutorでのプログラム実行方法」に従って実行する
  3. MatomeクラスとBaraクラスがともにProductインターフェイスに準拠し、totalメソッドを実装していることを確認する

ソースコード

interface Product {
    int total();
}

class Matome implements Product {
    int number;
    int unit;

    public int total() {
        return number * unit;
    }
}

class Bara implements Product {
    int price;

    public int total() {
        return price;
    }
}

public class Main {
    public static void main(String[] args) {
        Matome m = new Matome();
        m.number = 5;
        m.unit = 100;

        Bara b = new Bara();
        b.price = 250;

        System.out.println(m.total());
        System.out.println(b.total());
    }
}

期待される出力

500
250

ヒント

演習4:インターフェイスとコレクション

インターフェイスとコレクション(ArrayList)を組み合わせ、異なるクラスのオブジェクトを同一のリストで扱う方法を学ぶ。

前提知識

この演習は演習3の発展である。ArrayList<インターフェイス名>と宣言することで、そのインターフェイスを実装したクラスのオブジェクトを格納できる。これにより、継承関係のないクラスのオブジェクトを同一リストで管理し、共通のメソッドを呼び出せる。

手順

  1. 以下のプログラムをJava Tutorのエディタに入力する
  2. 「Java Tutorでのプログラム実行方法」に従って実行する
  3. ArrayList<Product>にMatomeとBaraの両方が格納され、それぞれのtotalメソッドが正しく動作することを確認する
import java.util.ArrayList;

interface Product {
    int total();
}

class Matome implements Product {
    int number;
    int unit;

    public int total() {
        return number * unit;
    }
}

class Bara implements Product {
    int price;

    public int total() {
        return price;
    }
}

public class Main {
    public static void main(String[] args) {
        ArrayList<Product> products = new ArrayList<Product>();

        Matome m = new Matome();
        m.number = 5;
        m.unit = 100;
        products.add(m);

        Bara b = new Bara();
        b.price = 250;
        products.add(b);

        int sum = 0;
        for (Product p : products) {
            sum = sum + p.total();
        }
        System.out.println(sum);
    }
}

期待される出力

750

ヒント

補足:デザインパターン

この節は発展的な学習項目として紹介する。演習は含まない。

デザインパターンとは、プログラム設計で繰り返し現れる問題とその解決策をまとめたものである。GoF(Gang of Four)の23パターンが知られている。

例として「Template Method」パターンがある。これは、サブクラスごとにメソッドの中身が異なり、スーパークラスではメソッドの中身を書かないというパターンである。

12. 時間,スリープ,疑似乱数,タイマー

資料:pi-12. 時間,スリープ,疑似乱数,タイマー [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習1:日時に関する計算と処理の一時停止

Javaで現在日時を取得する方法、日時に対する加算計算、およびThread.sleepによる処理の一時停止を習得する。

課題1-1:現在日時の取得

  1. GDB onlineで新しいJavaプログラムを作成する
  2. 以下のソースコードを入力する
public class Main {
    public static void main(String[] args) {
        java.time.LocalDateTime d;
        d = java.time.LocalDateTime.now();
        System.out.println(d);
    }
}
  1. 実行して、表示された日時を確認する

課題1-2:日時の加算計算

  1. 以下のソースコードを入力する
public class Main {
    public static void main(String[] args) {
        java.time.LocalDateTime d;
        d = java.time.LocalDateTime.now();
        System.out.println(d);
        System.out.println(d.plusHours(1));
        System.out.println(d.plusMinutes(1));
        System.out.println(d.plusSeconds(1));
    }
}
  1. 実行して、現在日時と各加算結果の関係を確認する

課題1-3:処理の一時停止

  1. 以下のソースコードを入力する
public class Main {
    public static void main(String[] args) {
        java.time.LocalDateTime d;
        d = java.time.LocalDateTime.now();
        System.out.println(d);
        try {
            Thread.sleep(2000);
        } catch(InterruptedException e) {}
        d = java.time.LocalDateTime.now();
        System.out.println(d);
    }
}
  1. 実行して、2つの日時表示の間に約2秒の差があることを確認する

ヒント

  • java.time.LocalDateTime.now()は現在の日時を取得するメソッドである
  • plusHours(1)、plusMinutes(1)、plusSeconds(1)はそれぞれ1時間後、1分後、1秒後の日時を返す
  • Thread.sleep()の引数はミリ秒単位である。1秒は1000ミリ秒であるため、2000を指定すると2秒間停止する
  • Thread.sleep()はInterruptedExceptionを発生させる可能性があるため、try-catch文で囲む必要がある
  • GDB onlineは世界標準時で動作するため、日本時間とは9時間ずれた時刻が表示される

演習2:スリープを用いたオブジェクトの移動

クラスとオブジェクトの基本を復習しながら、for文とThread.sleepを組み合わせた繰り返し処理を習得する。

課題2-1:Ballクラスの基本動作確認

  1. 以下のソースコードを入力する。Ballクラスは属性x、yを持ち、moveメソッドでxを2、yを3増加させる
class Ball {
    double x;
    double y;
    public Ball(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void move() {
        this.x = this.x + 2;
        this.y = this.y + 3;
    }
    public void printout() {
        System.out.printf("%f %f\n", this.x, this.y);
    }
}

public class Main {
    public static void main(String[] args) {
        Ball b = new Ball(0, 0);
        b.printout();
        b.move();
        b.printout();
    }
}
  1. 実行して、移動前の座標(0, 0)と移動後の座標(2, 3)を確認する

課題2-2:繰り返しとスリープの組み合わせ

  1. 以下のソースコードを入力する。for文とThread.sleepを組み合わせて、10回の移動を1秒間隔で実行する
class Ball {
    double x;
    double y;
    public Ball(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void move() {
        this.x = this.x + 2;
        this.y = this.y + 3;
    }
    public void printout() {
        System.out.printf("%f %f\n", this.x, this.y);
    }
}

public class Main {
    public static void main(String[] args) {
        Ball b = new Ball(0, 0);
        b.printout();
        for(int i = 1; i <= 10; i++) {
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) {}
            b.move();
            b.printout();
        }
    }
}
  1. 実行して、1秒ごとに座標が更新されることを確認する
  2. 10回の移動後、最終座標が(20, 30)になることを確認する

ヒント

  • for文の中でThread.sleep(1000)を呼び出すことで、各繰り返しの前に1秒の待機時間を設けている
  • moveメソッドを10回呼び出すと、xは2×10=20、yは3×10=30増加する
  • printoutメソッドの\nは改行を意味する

演習3:疑似乱数の生成

java.util.Randomクラスを用いて、ランダムな数値を生成する方法を習得する。

課題3-1:乱数の生成

  1. 以下のソースコードを入力する
public class Main {
    public static void main(String[] args) {
        int a;
        java.util.Random r = new java.util.Random();
        a = r.nextInt(10);
        System.out.println(a);
    }
}
  1. 実行して、0から9までの数値が表示されることを確認する
  2. 複数回実行して、実行のたびに異なる値が表示されることを確認する

ヒント

  • 疑似乱数とは、コンピュータのアルゴリズムによって生成されるランダムな数である。再現が可能であるため「疑似」と呼ばれる
  • nextInt(10)は0から9までの10通りの整数の中から1つをランダムに返す。引数で範囲を指定する
  • java.util.Randomのオブジェクトを生成してからnextIntメソッドを呼び出す

演習4:マルチスレッド

Threadクラスを継承して複数の処理を並行実行する方法を習得する。シングルスレッドとは単一の処理の流れであり、マルチスレッドとは複数の処理の流れである。本演習では、演習1で学んだThread.sleepを応用しながら、両者の違いを理解する。

課題4-1:シングルスレッドの動作確認

  1. 以下のソースコードを入力する
public class Main {
    public static void main(String[] args) {
        for(int i = 0; i < 100; i++) {
            try {
                Thread.sleep(1000);
            } catch(InterruptedException e) {}
            System.out.println("Hello");
        }
    }
}
  1. 実行して、1秒ごとに「Hello」が表示されることを確認する
  2. これはシングルスレッドであり、処理が順番に実行される

課題4-2:マルチスレッドの基本(1つの別スレッド)

  1. 以下のソースコードを入力する。ThreadクラスのサブクラスMorningを定義し、runメソッドに別スレッドで実行する処理を記述する
class Morning extends Thread {
    public void run() {
        for(int i = 0; i < 50; i++) {
            try {
                Thread.sleep(2000);
            } catch(InterruptedException e) {}
            System.out.println("Morning");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Morning m = new Morning();
        m.start();
    }
}
  1. 実行して、2秒ごとに「Morning」が表示されることを確認する

課題4-3:マルチスレッドの拡張(2つの別スレッド)

  1. 以下のソースコードを入力する。2つのスレッド(MorningとHello)を並行して実行する
class Morning extends Thread {
    public void run() {
        for(int i = 0; i < 50; i++) {
            try {
                Thread.sleep(2000);
            } catch(InterruptedException e) {}
            System.out.println("Morning");
        }
    }
}

class Hello extends Thread {
    public void run() {
        for(int i = 0; i < 50; i++) {
            try {
                Thread.sleep(3000);
            } catch(InterruptedException e) {}
            System.out.println("Hello");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Morning m = new Morning();
        m.start();
        Hello h = new Hello();
        h.start();
    }
}
  1. 実行して、「Morning」が2秒ごと、「Hello」が3秒ごとに表示されることを確認する
  2. 2つの出力が混在して表示されることで、並行処理が行われていることを確認する

ヒント

  • スレッドとは処理の流れのことである。通常のプログラムはシングルスレッドで順番に処理が実行される
  • マルチスレッドでは複数の処理を並行して実行できる。スレッド数は3つ以上にすることも可能である
  • Javaでマルチスレッドを実現するには、標準ライブラリのThreadクラスを継承したサブクラスを定義する
  • runメソッドに別スレッドで実行したい処理を記述する
  • start()メソッドを呼び出すと新しいスレッドが起動し、runメソッドが実行される

13. 今までの総まとめ

資料:pi-13. 今までの総まとめ [PDF], [パワーポイント]

演習パート(クリックして展開)

事前準備:Java Tutorの起動と操作

起動手順

  1. ウェブブラウザを起動する
  2. https://pythontutor.com/java.html を開く
  3. 編集画面が表示されることを確認する

実行手順

  1. 編集画面でプログラムを入力する
  2. 「Visualize Execution」をクリックする
  3. 「Last」をクリックする
  4. 実行結果を確認する
  5. 「Edit this code」をクリックして編集画面に戻る

注意点

演習13-1:式の抽象化とメソッド

変数を使って複数の類似した式を1つにまとめる「抽象化」の考え方を理解し、メソッドとして定義する方法を習得する。

用語

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
  2. 「はじめに」の操作手順に従い、プログラムを実行する
  3. 出力結果を確認する
public class YourClassNameHere {
    public static double foo(double a) {
        return a * 1.1;
    }
    public static void main(String[] args) {
        System.out.printf("%f\n", foo(100));
        System.out.printf("%f\n", foo(150));
        System.out.printf("%f\n", foo(400));
    }
}

期待される出力

110.000000
165.000000
440.000000

ヒント

演習13-2:クラスとコンストラクタ

クラスの定義方法と、コンストラクタを用いたオブジェクト生成を理解する。

用語

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
  2. 「はじめに」の操作手順に従い、プログラムを実行する
  3. 2つのCircleオブジェクトの情報が出力されることを確認する
class Circle {
    double x;
    double y;
    double r;
    String color;
    public Circle(double x, double y, double r, String color) {
        this.x = x;
        this.y = y;
        this.r = r;
        this.color = color;
    }
    public void printout() {
        System.out.printf("%f %f %f %s\n", this.x, this.y, this.r, this.color);
    }
}
public class YourClassNameHere {
    public static void main(String[] args) {
        Circle x = new Circle(2, 4, 3, "green");
        Circle y = new Circle(8, 10, 1, "blue");
        x.printout();
        y.printout();
    }
}

期待される出力

2.000000 4.000000 3.000000 green
8.000000 10.000000 1.000000 blue

ヒント

演習13-3:スーパークラス・サブクラス・継承

継承の仕組みを理解し、extendsキーワードを用いたクラスの親子関係の定義方法を習得する。

用語

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
  2. 「はじめに」の操作手順に従い、プログラムを実行する
  3. 演習13-2と同じ出力結果になることを確認する
  4. FigureクラスとCircleクラスの関係を確認する
class Figure {
    double x;
    double y;
    String color;
    public Figure(double x, double y, String color) {
        this.x = x;
        this.y = y;
        this.color = color;
    }
}
class Circle extends Figure {
    double r;
    public Circle(double x, double y, double r, String color) {
        super(x, y, color);
        this.r = r;
    }
    public void printout() {
        System.out.printf("%f %f %f %s\n", this.x, this.y, this.r, this.color);
    }
}
public class YourClassNameHere {
    public static void main(String[] args) {
        Circle x = new Circle(2, 4, 3, "green");
        Circle y = new Circle(8, 10, 1, "blue");
        x.printout();
        y.printout();
    }
}

期待される出力

2.000000 4.000000 3.000000 green
8.000000 10.000000 1.000000 blue

ヒント

演習13-4:クラスの抽象化

類似した複数のクラスから共通属性を抽出してスーパークラスにまとめる「クラスの抽象化」を理解する。CircleとRectangleという2つのサブクラスを持つクラス階層を実装する。

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
  2. 「はじめに」の操作手順に従い、プログラムを実行する
  3. CircleオブジェクトとRectangleオブジェクトの情報が出力されることを確認する

ソースコード

class Figure {
    double x;
    double y;
    String color;
    public Figure(double x, double y, String color) {
        this.x = x;
        this.y = y;
        this.color = color;
    }
}
class Circle extends Figure {
    double r;
    public Circle(double x, double y, double r, String color) {
        super(x, y, color);
        this.r = r;
    }
    public void printout() {
        System.out.printf("%f %f %f %s\n", this.x, this.y, this.r, this.color);
    }
}
class Rectangle extends Figure {
    double width;
    double height;
    public Rectangle(double x, double y, double w, double h, String color) {
        super(x, y, color);
        this.width = w;
        this.height = h;
    }
    public void printout() {
        System.out.printf("%f %f %f %f %s", this.x, this.y, this.width, this.height, this.color);
    }
}
public class YourClassNameHere {
    public static void main(String[] args) {
        Circle x = new Circle(2, 4, 3, "green");
        Rectangle a = new Rectangle(6, 4, 1, 2, "blue");
        x.printout();
        a.printout();
    }
}

期待される出力

2.000000 4.000000 3.000000 green
6.000000 4.000000 1.000000 2.000000 blue

ヒント

演習13-5:配列と繰り返し、疑似乱数

配列とforループを用いた繰り返し処理、および疑似乱数の生成方法を理解する。

用語

演習13-5a:配列と繰り返し

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
  2. 「はじめに」の操作手順に従い、プログラムを実行する
  3. 配列xの各要素に1.1を掛けた結果が出力されることを確認する
public class YourClassNameHere {
    public static void main(String[] args) {
        double x[] = {8, 6, 4, 2, 3};
        double y[] = {0, 0, 0, 0, 0};
        int i;
        for(i=0; i<=4; i++) {
            y[i] = x[i] * 1.1;
        }
        for(i=0; i<=4; i++) {
            System.out.println(y[i]);
        }
    }
}

期待される出力

8.8
6.6000000000000005
4.4
2.2
3.3000000000000003

注意:浮動小数点数の計算では、わずかな誤差が生じることがある。

ヒント

演習13-5b:疑似乱数

手順

  1. Java Tutorの編集画面で以下のプログラムを入力する
  2. 「はじめに」の操作手順に従い、プログラムを実行する
  3. 0から99の範囲の整数が10個出力されることを確認する
import java.util.Random;

public class YourClassNameHere {
    public static void main(String[] args) {
        Random r = new Random();
        int i, a;
        for(i=0; i<10; i++) {
            a = r.nextInt(100);
            System.out.println(a);
        }
    }
}

期待される出力

0から99の範囲の整数が10個出力される。疑似乱数のため、実行するたびに異なる値が出力される。

ヒント

まとめ

概念説明
オブジェクトコンピュータでの操作や処理の対象となるもの
メソッドオブジェクトに属する操作や処理
クラス同じ種類のオブジェクトの集まりを定義するもの
コンストラクタオブジェクトの生成を行うメソッド
継承スーパークラスの属性とメソッドをサブクラスが受け継ぐこと
抽象化類似した複数の要素から共通部分を抽出してまとめること

14. イベント,イベントハンドラ,ソケット通信

資料:pi-14. イベント,イベントハンドラ,ソケット通信 [PDF], [パワーポイント]

演習パート(クリックして展開)

使用するオンライン環境

GDB online(https://www.onlinegdb.com)を使用する。オンラインサービスのため、機密性の高いプログラムの取り扱いには注意が必要である。

GDB onlineの基本操作

  1. ウェブブラウザでhttps://www.onlinegdb.comを開く
  2. 画面上部の「Language」で「Java」を選択する
  3. エディタにソースコードを入力する
  4. 「Run」ボタンをクリックして実行する

イベントとは

イベント(event)とは、プログラム実行中に発生する出来事を指す。 代表的な例として、タイマーによる時間経過、キーボードやマウスの操作がある。

イベントハンドラとは

イベントハンドラ(event handler)とは、イベント発生時に実行される処理を指す。 プログラムでは、特定のイベントに対して実行すべき処理を事前に登録しておく。 イベントが発生すると、登録された処理が自動的に実行される。

演習1:タイマーイベント(基礎)

TimerTaskクラスを用いて、一定時間ごとに処理を実行するプログラムを作成する。

使用環境

この演習ではGDB online(https://www.onlinegdb.com)を使用する。

演習1-1:処理の一時停止

タイマーイベントのプログラムでは、メインの処理を一定時間待機させる必要がある。 待機させないと、メインの処理が終了した時点でプログラム全体が終了し、タイマーイベントが発生しなくなるためである。 ここでは、Thread.sleepメソッドを用いた処理の一時停止を確認する。

手順

  1. ウェブブラウザでhttps://www.onlinegdb.com を開く
  2. 「Language」で「Java」を選ぶ
  3. 以下のソースコードを入力する
  4. 「Run」をクリックして実行する
  5. 「start」と表示されることを確認する
import java.util.*;

public class Main {
    public static void main(String[] args) {
        System.out.println("start");
        try {
            Thread.sleep(100000);
        } catch(InterruptedException e) {}
    }
}

ヒント

Thread.sleepメソッドの引数はミリ秒単位である。100000ミリ秒は100秒に相当する。 try-catch文で囲んでいるのは、Thread.sleepがInterruptedException(割り込み例外)をスローする可能性があるためである。

演習1-2:タイマーイベントの実装

手順

  1. 演習1-1で使用したGDB onlineの画面を引き続き使用する
  2. 以下のソースコードに書き換える
  3. 「Run」をクリックして実行する
  4. 「start」と表示された後、定期的に「hello」が表示されることを確認する
import java.util.*;

class MyTask extends TimerTask {
    public void run() {
        System.out.println("hello");
    }
}

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new MyTask(), 100, 500);
        System.out.println("start");
        try {
            Thread.sleep(100000);
        } catch(InterruptedException e) {}
    }
}

ヒント

TimerTaskはJava標準ライブラリのクラスで、タイマーイベントのイベントハンドラを定義するために使用する。 MyTaskクラスはTimerTaskを継承し、runメソッドにイベント発生時の処理を記述する。

timer.schedule(new MyTask(), 100, 500)の各引数の意味は以下のとおりである。 第1引数は実行するタスク、第2引数は最初のイベント発生までの待機時間(ミリ秒)、第3引数はその後のイベント発生間隔(ミリ秒)である。 この例では、0.1秒後に最初のイベントが発生し、その後0.5秒間隔でイベントが発生する。

タイマーイベントはメインの処理とは別のスレッド(実行の流れ)で動作する。 これをマルチスレッド実行と呼ぶ。 メインの処理がThread.sleepで待機している間も、タイマーイベントは別スレッドで定期的に実行される。

演習2:タイマーイベント(応用)

クラスとタイマーイベントを組み合わせ、オブジェクトの状態を定期的に更新するプログラムを作成する。

Ballクラスの説明

この演習で使用するBallクラスは、x座標とy座標を属性として持つ。 moveメソッドは、x座標の値を2増やし、y座標の値を3増やす。 printoutメソッドは、現在の座標を表示する。

演習2-1:Ballクラスの動作確認

手順

  1. GDB onlineで「Java」が選択されていることを確認する
  2. 以下のソースコードを入力する
  3. 「Run」をクリックして実行する
  4. Ballオブジェクトの座標が表示され、moveメソッド呼び出し後に座標が変化することを確認する
class Ball {
    double x;
    double y;
    public Ball(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void move() {
        this.x = this.x + 2;
        this.y = this.y + 3;
    }
    public void printout() {
        System.out.printf("%f %f\n", this.x, this.y);
    }
}

public class Main {
    public static void main(String[] args) {
        Ball b = new Ball(0, 0);
        b.printout();
        b.move();
        b.printout();
    }
}

ヒント

実行結果は以下のようになる。 1行目は初期座標「0.000000 0.000000」、2行目はmoveメソッド呼び出し後の座標「2.000000 3.000000」である。

演習2-2:タイマーイベントによる定期的な移動

手順

  1. 演習2-1のソースコードを以下のように書き換える
  2. 「Run」をクリックして実行する
  3. 「start」と表示された後、0.5秒ごとにBallの座標が変化して表示されることを確認する
import java.util.*;

class Ball {
    double x;
    double y;
    public Ball(double x, double y) {
        this.x = x;
        this.y = y;
    }
    public void move() {
        this.x = this.x + 2;
        this.y = this.y + 3;
    }
    public void printout() {
        System.out.printf("%f %f\n", this.x, this.y);
    }
}

class MyTask extends TimerTask {
    Ball b;
    public MyTask() {
        super();
        this.b = new Ball(0, 0);
    }
    public void run() {
        b.move();
        b.printout();
    }
}

public class Main {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new MyTask(), 100, 500);
        System.out.println("start");
        try {
            Thread.sleep(100000);
        } catch(InterruptedException e) {}
    }
}

ヒント

MyTaskクラスのコンストラクタでBallオブジェクトを生成し、runメソッド内でmoveとprintoutを呼び出している。 0.5秒ごとにイベントが発生し、そのたびにBallの座標が更新されて表示される。

ソケットとは

ソケット(socket)は、機器間の通信やプロセス間通信に使用するインターフェースである。

インターネット通信の仕組み

インターネット通信では、サーバ(要求を待ち受ける側)とクライアント(要求を送る側)が存在する。

サーバ側では、実行中のプログラムがサーバソケットにバインド(bind:結び付け)される。 サーバソケットには特定のポート番号が割り当てられる。 サーバは接続要求が来るのを待つ。これをaccept(受け入れ)と呼ぶ。

クライアント側では、サーバのIPアドレス(またはサイト名)とポート番号を指定して通信を開始する。

サーバソケットとデータ送受信用ソケット

サーバソケットは接続要求を待ち受けるためのソケットである。 データ送受信用ソケットは、実際のデータのやり取りに使用するソケットで、サーバソケットとは別のものである。

HTTPプロトコルの基本

HTTP(Hypertext Transfer Protocol)は、WebブラウザとWebサーバ間の通信に使用するプロトコルである。 クライアントがリクエスト(要求)を送信し、サーバがレスポンス(応答)を返す形式で通信が行われる。 HTTPの標準ポート番号は80である。

演習3:ソケット通信

Javaでソケット通信を行い、Webサーバからデータを取得するプログラムの動作を確認する。

使用環境

この演習ではpaiza.io(https://paiza.io/)を使用する。

手順

  1. ウェブブラウザでhttps://paiza.io/ を開く
  2. 表示が英語の場合は日本語に切り替える
  3. 「コード作成を試してみる」をクリックする
  4. 左上のボタンをクリックしてメニューを開き、「Java」を選ぶ
  5. 以下のソースコードを入力する
  6. 「実行」ボタンをクリックして実行する
  7. サーバからのレスポンスが表示されることを確認する
import java.util.*;
import java.net.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        try {
            Socket s = new Socket("www.kkaneko.jp", 80);
            BufferedReader in = new BufferedReader
                (new InputStreamReader(s.getInputStream()));
            BufferedWriter out = new BufferedWriter
                (new OutputStreamWriter(s.getOutputStream()));
            out.write("GET /index.html HTTP/1.0\r\n");
            out.write("Host: www.kkaneko.jp:80\r\n");
            out.write("\r\n");
            out.flush();
            System.out.println(in.readLine());
            System.out.println(in.readLine());
            System.out.println(in.readLine());
            System.out.println(in.readLine());
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

ヒント

Socket s = new Socket("www.kkaneko.jp", 80)で、サーバのサイト名とポート番号を指定して接続を確立する。

BufferedReaderはデータ受信用、BufferedWriterはデータ送信用のクラスである。 InputStreamReaderとOutputStreamWriterは、バイト列と文字列を相互に変換するためのクラスである。 getInputStreamメソッドで受信用のストリーム(データの流れ)を、getOutputStreamメソッドで送信用のストリームを取得する。

out.writeでHTTPリクエストを送信している。 HTTP/1.0では、リクエストの終わりを空行(\r\n)で示す。 out.flushは、バッファ(一時的な保存領域)に蓄積されたデータを実際に送信するためのメソッドである。

in.readLineで、サーバからのレスポンスを1行ずつ読み取る。

まとめ

イベントとイベントハンドラについては、イベント発生時に実行する処理を事前に登録する仕組みを学んだ。 TimerTaskクラスを用いることで、定期的な処理をマルチスレッドで実行できる。

ソケット通信については、ソケットを用いてインターネット経由でデータを送受信する方法を学んだ。 サーバ側ではプログラムをサーバソケットにバインドし、クライアント側ではサーバのIPアドレス(またはサイト名)とポート番号を指定して通信を開始する。

15. カプセル化,MVCモデル,オブジェクトのマッピング

資料:pi-15. カプセル化,MVCモデル,オブジェクトのマッピング [PDF], [パワーポイント]

演習パート(クリックして展開)

使用するオンライン環境

GDB online(https://www.onlinegdb.com)を使用する。オンラインサービスのため、機密性の高いプログラムの取り扱いには注意が必要である。

GDB onlineの基本操作

  1. ウェブブラウザでhttps://www.onlinegdb.comを開く
  2. 画面上部の「Language」で「Java」を選択する
  3. エディタにソースコードを入力する
  4. 「Run」ボタンをクリックして実行する

カプセル化

カプセル化(encapsulation)とは、オブジェクトが持つ属性とメソッドのうち、必要なもののみを他のオブジェクトに公開する仕組みである。外部から直接変更されたくないデータを保護し、オブジェクトの内部構造を隠蔽できる。Java では public(公開)と private(非公開)の指定により、属性やメソッドへのアクセス制御を行う。

MVC モデル

MVC モデルとは、プログラムを以下の3つの要素に分離して設計する手法である。

この分離により、プログラムの見通しが良くなる。

演習1:MVC モデルの実装(ビューなし)

MVC モデルにおけるモデル部分(Person クラス、Meibo クラス)とコントローラー部分(Main クラス)を実装し、クラス間の連携を理解する。

手順

  1. GDB online で新規 Java プロジェクトを開く
  2. 以下のソースコードを入力する
  3. 「Run」ボタンをクリックして実行する
  4. 登録した名簿データが出力されることを確認する
import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;

class Person {
    String name;
    String address;
    public Person(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public void printout() {
        System.out.printf("%s %s\n", this.name, this.address);
    }
}

class Meibo {
    HashMap<Integer, Person> m;
    public Meibo(HashMap<Integer, Person> m) {
        this.m = m;
    }
    public void add(int id, String name, String address) {
        m.put(id, new Person(name, address));
    }
    public void printout() {
        for(Integer i : this.m.keySet()) {
            System.out.printf("%d, ", i);
            this.m.get(i).printout();
        }
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        HashMap<Integer, Person> m = new HashMap<Integer, Person>();
        Meibo a = new Meibo(m);
        a.add(1, "XX", "Fukuyama");
        a.add(2, "YY", "Okayama");
        a.printout();
    }
}

ヒント

演習1の課題

現在の実装では、モデルが直接出力を担当している。このため、表示形式を変更するにはモデルのコードを修正する必要がある。また、モデル内のすべてのデータ(ID を含む)が出力されており、一部のデータのみを表示したい場合に対応しにくい。演習2では、ビューを導入してこの課題を解決する。

演習2:MVC モデルの実装(ビューあり)

View クラスを追加し、モデルとビューを分離した設計を体験する。

手順

  1. 演習1のソースコードをベースにする
  2. View クラスを追加する
  3. Main クラスを修正し、View クラスを使用するように変更する
  4. 「Run」ボタンをクリックして実行する
  5. 実行結果を確認し、演習1との違いを考察する

ソースコード

import java.util.HashMap;
import java.util.Iterator;
import java.util.ArrayList;

class Person {
    String name;
    String address;
    public Person(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public void printout() {
        System.out.printf("%s %s\n", this.name, this.address);
    }
}

class Meibo {
    HashMap<Integer, Person> m;
    public Meibo(HashMap<Integer, Person> m) {
        this.m = m;
    }
    public void add(int id, String name, String address) {
        m.put(id, new Person(name, address));
    }
    public void printout() {
        for(Integer i : this.m.keySet()) {
            System.out.printf("%d, ", i);
            this.m.get(i).printout();
        }
    }
}

class View {
    ArrayList<Person> v;
    public View() {
    }
    public void update(Meibo meibo) {
        this.v = new ArrayList<Person>();
        for(Integer i: meibo.m.keySet()) {
            v.add(meibo.m.get(i));
        }
    }
    public void printout() {
        for(Person p: this.v) {
            System.out.printf("%s %s\n", p.name, p.address);
        }
    }
}

public class Main {
    public static void main(String[] args) throws Exception {
        HashMap<Integer, Person> m = new HashMap<Integer, Person>();
        Meibo a = new Meibo(m);
        a.add(1, "XX", "Fukuyama");
        a.add(2, "YY", "Okayama");
        View v = new View();
        v.update(a);
        v.printout();
    }
}

ヒント

発展学習

演習で学んだ MVC モデルは、実際の開発でどのように活用されるか。ここでは2つの応用を紹介する。

オブジェクトのマッピング

Java オブジェクトは、リレーショナルデータベースや DOM オブジェクト(Document Object Model:文書をノードの階層構造として表現するモデル)にマッピング(対応付け)できる。これにより、データベースの検索結果を Java オブジェクトとして扱ったり、Web ブラウザでの表示を動的に変更したりできる。

MVC モデルに対応するフレームワーク

Java には MVC モデルに適したフレームワーク(アプリケーションの土台となるソフトウェア)が多数ある。代表的なものとして Struts、JSF(Java Server Faces)、Spring Framework がある。これらを使用すると、Web アプリケーションを効率的に開発できる。

16. プログラムのテスト,アサーション,例外処理

資料:pi-16. プログラムのテスト,アサーション,例外処理 [PDF], [パワーポイント]

演習パート(クリックして展開)

使用するオンライン環境

GDB online(https://www.onlinegdb.com)を使用する。オンラインサービスのため、機密性の高いプログラムの取り扱いには注意が必要である。

GDB onlineの基本操作

  1. ウェブブラウザでhttps://www.onlinegdb.comを開く
  2. 画面上部の「Language」で「Java」を選択する
  3. エディタにソースコードを入力する
  4. 「Run」ボタンをクリックして実行する

プログラム設計レシピ

プログラム設計レシピは、プログラムを設計するときに考えておくべきこと、実行すべきことをまとめたものである。次の4段階で構成される。

第1段階:分析

メソッドに名前を付け、入力と出力を明らかにする。

第2段階:仕様

メソッドの性能や機能の条件を定める。

第3段階:例

どのような入力に対して、どのような出力が得られるべきかを具体的に示す。例があることで、プログラムが書きやすくなり、他者がプログラムを理解しやすくなる。また、テストの実施にも利用できる。

第4段階:テスト

プログラムが設計どおりに動作するかを確認する。

演習:リングの面積プログラム

目的

Ringクラスを作成し、areaメソッドでリングの面積を計算する。設計レシピの4段階を実践する。

リングの面積

リングは外径r2と内径r1を持つドーナツ状の図形である。面積は次の式で計算する。

(r2 * r2 - r1 * r1) * 3.14

設計レシピの適用

段階内容
分析メソッド名:area、入力:なし(属性r1, r2を使用)、出力:数値1つ(面積)
仕様r1を内径、r2を外径とするリングの面積を求める
r1 = 3、r2 = 5のとき、50.24が求まる
テストプログラムを実行し、期待どおりの結果が得られることを確認する

手順

  1. GDB onlineを開き、Javaを選択する
  2. 次のソースコードを入力する
class Ring {
    double r1;
    double r2;
    public Ring(double r1, double r2) {
        this.r1 = r1;
        this.r2 = r2;
    }
    public double area() {
        double x;
        x = (this.r2 * this.r2 - this.r1 * this.r1) * 3.14;
        return x;
    }
}
public class Main {
    public static void main(String[] args) {
        Ring a = new Ring(3, 5);
        System.out.println(a.area());
    }
}
  1. 「Run」をクリックして実行する
  2. 出力が50.24であることを確認する

確認ポイント

2. エラーの種類とテスト

プログラムを実行して動作を観察する。

構文エラー

言語の書式に合っていない場合に発生する。プログラムを実行しようとすると、実行できずにエラーメッセージが表示される。例えば、スペルミスや括弧の不足がこれに該当する。

実行エラー

プログラムの実行中に発生し、出力が得られない。実行するとエラーメッセージが表示されたり、プログラムが停止したように見えたりする。

論理的エラー

プログラムは実行できるが、出力が仕様に合致しない。プログラムを実行してテストすることで発見する。

観察:実行エラーを含むプログラム

次のプログラムには実行エラーが含まれている。どこに問題があるか考えてから実行し、確認すること。

class Ring {
    double r1;
    double r2;
    public Ring(double r1, double r2) {
        this.r1 = r1;
        this.r2 = r2;
    }
    public double area() {
        double x;
        x = (this.r2 * this.r2 - this.r1 * this.r1) / 0;
        return x;
    }
}
public class Main {
    public static void main(String[] args) {
        Ring a = new Ring(3, 5);
        System.out.println(a.area());
    }
}

観察のポイント

アサーションとは

アサーションは「必ず成立しているはずのこと」を記述したものである。論理的エラーの発見に役立つ。

Javaでの記述方法

assert x >= 0 : "error, x < 0 in area()";

この例では「x >= 0」がアサーションである。この条件が成立しない場合、「error, x < 0 in area()」というメッセージが表示される。

注意

アサーションの機能はGDB onlineで動作させることが難しい。

例外処理とは

例外処理は、不測の事態に対応するための仕組みである。

不測の事態の例

Javaでの記述方法

throws Exception

メソッド内で例外が発生する可能性があることを宣言する。

throw new Exception

例外を発生させる。

try-catch構文

try {
    処理
} catch(Exception e) {
    例外処理
}

tryブロック内で例外が発生した場合、catchブロック内の例外処理が実行される。

学習のまとめ

この章で学んだ内容は次のとおりである。

17. プログラム設計

資料:pi-17. プログラム設計 [PDF], [パワーポイント]

演習パート(クリックして展開)

重要概念

Javaでは、クラスを定義し、クラス間に継承関係を設けることで、コードの再利用性を高められる。UMLクラス図は、このようなクラス構造を設計段階で視覚的に表現する手法である。本節では、演習に必要な概念を確認する。

クラス定義

クラス定義には、属性の定義(属性名とデータ型)、コンストラクタの定義、メソッドの定義を含める。コンストラクタとは、オブジェクトを生成するためのメソッドである。

クラス階層と継承

クラス階層とは、複数のクラスが親子関係を形成することである。継承とは、親クラス(スーパークラス)の属性とメソッドを子クラス(サブクラス)が受け継ぐ仕組みである。継承により、共通する属性やメソッドを親クラスにまとめ、子クラスでは差分のみを定義できる。

UMLクラス図

UML(Unified Modeling Language)のクラス図は、プログラムの設計図の記法の一つである。クラス図には、クラスの属性、操作、クラス間の相互関係を記述する。

クラス間の相互関係には以下の2種類がある。

演習1:UMLクラス図の作成

draw.ioを使用してUMLクラス図を作成する。この演習を通じて、クラスの属性と操作の記述方法、および親子関係の表現方法を身につける。

使用ツール

draw.io:チャートや設計図を作成できるオンラインサービスである。

URL: https://www.draw.io

課題

以下の仕様に従い、3つのクラスとその親子関係を表すクラス図を作成しなさい。

クラス名親クラス属性操作
Ballなしx, y, colormove, reset
CircleBallr(継承のみ)
RectangleBallw, h(継承のみ)

注意事項

UMLクラス図では、子クラスには親クラスから継承する属性や操作を記載しない。子クラス固有の属性と操作のみを記載する。

手順

  1. Webブラウザで https://www.draw.io を開く
  2. 保存先の設定画面が表示されたら「Decide later」を選ぶ
  3. 「Create New Diagram」を選び、「Blank Diagram」を選択して「Create」をクリックする
  4. 左側のシェイプ一覧で「UML」を展開する
  5. 「3段の四角」のシェイプを編集画面にドラッグし、Ballクラスを作成する
    • 上段:クラス名「Ball」
    • 中段:属性「x」「y」「color」
    • 下段:操作「move」「reset」
  6. 同様にCircleクラスとRectangleクラスを作成する
    • 属性を増やす場合:属性を選択し、右クリックメニューで「Duplicate」を選ぶ
    • 属性を減らす場合:属性を選択し、右クリックメニューで「Delete」を選ぶ
  7. 親子関係を表す線を引く
    • 子クラス(CircleまたはRectangle)から親クラス(Ball)へマウスで線を引く
    • 線の書式設定で、終端を三角形の白抜き矢印に変更する
  8. 完成したクラス図を確認する

ヒント

演習2:UMLクラス図からJavaプログラム作成

UMLクラス図に基づいてJavaプログラムを作成する。この演習を通じて、クラス定義、継承、関連をJavaで実装する方法を身につける。

使用ツール

GDB online:Javaなどのプログラミング言語を実行できるオンラインサービスである。

URL: https://www.onlinegdb.com

注意:オンラインサービスであるため、機密性の高いプログラムを扱う際は注意が必要である。

課題

以下の仕様に従い、3つのクラスを定義し、動作を確認しなさい。

クラス名親クラス属性操作
Addressなしaddressprint
Personなしname, a(Address型)print
StudentPersonidprint

PersonクラスはAddressクラスと関連を持つ。これは、PersonクラスがAddress型の属性を持つことで実装する。関連の多重度は、Person側が1、Address側が0..1である(1人のPersonに対してAddressは0個または1個)。

手順

  1. Webブラウザで https://www.onlinegdb.com を開く
  2. 「Language」で「Java」を選ぶ
  3. エディタにAddressクラスを入力する:
    class Address {
        String address;
        public Address(String address) {
            this.address = address;
        }
        public void print() {
            System.out.println(this.address);
        }
    }
    
  4. 続けてPersonクラスを入力する:
    class Person {
        String name;
        Address a;
        public Person(String name, Address a) {
            this.name = name;
            this.a = a;
        }
        public void print() {
            System.out.println(this.name);
            this.a.print();
        }
    }
    
  5. 続けてStudentクラスを入力する:
    class Student extends Person {
        int id;
        public Student(String name, Address a, int id) {
            super(name, a);
            this.id = id;
        }
        public void print() {
            System.out.println(this.name);
            System.out.println(this.id);
            this.a.print();
        }
    }
    
  6. 続けてMainクラスを入力する:
    public class Main {
        public static void main(String[] args) {
            Address a = new Address("Fukuoka");
            Student s = new Student("kaneko", a, 10);
            s.print();
        }
    }
    
  7. 「Run」をクリックして実行する
  8. 実行結果を確認する

ヒント

よくある間違い

期待される実行結果

kaneko
10
Fukuoka