復習 (3)

今回の内容

今回はこのコースの内容すべての復習を行います。知識に抜けがないかチェックしておきましょう。

復習

入出力

「入出力」の回では、次のように入力ダイアログとメッセージダイアログを表示する簡単なプログラムを紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class First {

    public static void main(String[] args) {
        new First().start();
    }

    void start() {
        String input = JOptionPane.showInputDialog("メッセージをどうぞ");
        JOptionPane.showMessageDialog(null, input);
    }
}

プログラムは、void start() {…}というstartメソッドのうち、ブロックと呼ばれる{…}の部分を書き換えていくつかの命令を書きます。ここでメッセージを表示する際には次のように書きます。

JOptionPane.showMessageDialog(null, <表示させる文字列>);

また、入力ダイアログを表示するには次のように書きます。

String <入力を記憶させる名前> = JOptionPane.showInputDialog(<表示させる文字列>);

式と変数

「式と変数」の回では、整数や実数、文字列などの値や、それらを計算で組み合わせる方法、変数を宣言してそれらの値を記憶させる方法などを紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class CircleArea {

    public static void main(String[] args) {
        new CircleArea().start();
    }

    void start() {
        String input = JOptionPane.showInputDialog("円の半径を入力");
        double radius = Double.parseDouble(input);
        JOptionPane.showMessageDialog(null, radius * radius * 3.14);
    }
}

変数を利用するにはプログラム中で次のように「変数の宣言」を行います。

String <変数名> = <文字列>;
int <変数名> = <整数>;
double <変数名> = <実数>;

変数に記憶させた値を利用するには、リテラルの代わりに宣言した変数の名前を指定します。なお、String, int, double をそれぞれ変数の「型」と呼び、変数に記憶させられる値の種類は、それぞれ型ごとに決められています。

その他に、整数や実数のリテラルや変数を組み合わせて、新しい値を作りだす方法を紹介しました。さきほどの例では、円の面積を求めるために「radius * radius * 3.14」という計算を行っています。

Javaでの書き方 算数での書き方 意味
a + b a + b aとbの和 (文字列を含む場合はaとbの結合)
a – b a - b aとbの差
a * b a × b aとbの積
a / b a ÷ b aとbの商

なお、入力ダイアログに入力された値は、文字列として取り扱うことになります。文字列のままでは上記のような計算が行えないため、整数や実数に変換して利用する方法を紹介しました。

int <変数名> = Integer.parseInt(<文字列>);
double <変数名> = Double.parseDouble(<文字列>);

条件分岐

「条件分岐」の回では、コンピューターに簡単な「判断」を行わせるプログラムを紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class SelectQuiz2 {

    public static void main(String[] args) {
        new SelectQuiz2().start();
    }

    void start() {
        String input = JOptionPane.showInputDialog("条件分岐をするには?"
            + "(1) if文 "
            + "(2) for文 ");
        int answer = Integer.parseInt(input);
        if (answer == 1) {
            JOptionPane.showMessageDialog(null, "正解です");
        }
        else if (answer == 2) {
            JOptionPane.showMessageDialog(null, "不正解です");
        }
        else {
            JOptionPane.showMessageDialog(null, "無効な値です");
        }
    }
}

条件分岐は、次のようにif文を使います。

if (<1つ目の条件式>) {
    <1つ目の条件が成立する場合の命令>
}
else if (<2つ目の条件式>) {
    <2つ目の条件が成立する場合の命令>
}
else if (<3つ目の条件式>) {
    <3つ目の条件が成立する場合の命令>
}

else {
    <すべての条件が成立しない場合の命令>
}

また、条件式では次のような値の比較を行えます。

Javaでの書き方 数学での書き方 意味
a == b a = b aはbと等しい
a != b a ≠ b aはbと等しくない
a < b a < b aはbより小さい
a > b a > b aはbより大きい
a <= b a ≦ b aはbより小さいか、等しい (以下)
a >= b a ≧ b aはbより大きいか、等しい (以上)

他には、この条件式を組み合わせて複雑な条件式を表現する方法についても紹介しました。

Javaでの書き方 数学での書き方 意味
A && B A ∩ B AかつB
A || B A ∪ B AまたはB

また、「関数」の回では、条件式として利用できるメソッドについても紹介しました。これは次のように宣言します。

boolean <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <trueまたはfalse>;
}

trueやfalseなどを「論理値」と呼び、論理値を返すメソッドはif文の条件式を書くところで起動できます。起動先のメソッドがtrueを返せば条件が成立したとみなされ、falseを返せば条件が成立しなかったとみなされます。また、先頭に ! をつけることでtrueとfalseを反転させられます。

if (<メソッドの名前>(<実引数の一覧>)) {
    <成立する場合の命令>
}
if (!<メソッドの名前>(<実引数の一覧>)) {
    <成立しない場合の命令>
}

メソッド

「手続き」の回と「関数」では、命令のかたまりを「メソッド」として切り出して、プログラムを分割する方法について紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class Add {

    public static void main(String[] args) {
        new Add().start();
    }

    void start() {
        String input1 = JOptionPane.showInputDialog("1つ目の整数を入力");
        String input2 = JOptionPane.showInputDialog("2つ目の整数を入力");
        int a = Integer.parseInt(input1);
        int b = Integer.parseInt(input2);
        int result = add(a, b);
        JOptionPane.showMessageDialog(null, "合計は" + result);
    }

    int add(int a, int b) {
        return a + b;
    }
}

メソッドを利用するには、まず次の形で「メソッドの宣言」を書きます。

void <メソッドの名前>(<仮引数の一覧>) {
    <命令>
}

メソッドが値を返す場合には、メソッド宣言のvoidの代わりに返す値の型を指定し、メソッドのブロックでreturn文を使って起動元に返す値を指定します。

<戻り値の型> <メソッドの名前>(<仮引数の一覧>) {
    <命令>
    return <起動元に渡す値>;
}

このメソッドに含まれる{ <命令> }の部分をブロックと呼びます。このブロックに含まれる命令はいくつでもよく、それぞれ上から順に処理されます。これらの命令を実行するには、該当するメソッドを下記の形式で起動します。

<メソッドの名前>(<実引数1>, <実引数2>, …)

すると、同じ名前を持つメソッドが起動し、それぞれの仮引数には対応する実引数の値が記憶されます。仮引数は通常の変数のように扱えますので、メソッドを起動する際に渡された値を、起動先のメソッドで利用できます。

配列と繰り返し

「値の列」の回では、プログラムで多数の値を取り扱う「配列」というものを紹介し、さらに「繰り返し」の回では配列の要素を集計する方法について紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class Sum {

    public static void main(String[] args) {
        new Sum().start();
    }

    void start() {
        int[] values = getValues();
        int total = 0;
        for (int i = 0; i < values.length; i++) {
            total = total + values[i];
        }
        JOptionPane.showMessageDialog(null, total);
    }

    int[] getValues() {
        int[] values = new int[5];
        values[0] = 10;
        values[1] = 20;
        values[2] = 30;
        values[3] = 40;
        values[4] = 50;
        return values;
    }
}

配列にはこれまでに紹介した整数や実数、または文字列などの値を複数記憶させられます。

int[] array = new int[10];
array[0] = 100;
array[1] = 200;
...

配列をプログラムから利用するには、まず配列を生成して変数に記憶させます。配列を生成する際には、配列が記憶できる値の種類と、長さ(記憶できる値の個数)を指定します。

int[] <変数の名前> = new int[<配列の長さ>];
double[] <変数の名前> = new double[<配列の長さ>];
String[] <変数の名前> = new String[<配列の長さ>];

配列に記憶させた個々の値を利用するには、変数名の後に角かっこでインデックスを指定します。

int element = array[5];

インデックスは整数で指定し、配列の最初の要素を参照する場合には0、最後の要素を参照する場合には(配列の長さ – 1)を指定します。この配列の長さは、変数名の後に「.length」と指定すればプログラム中から利用できます。

配列のそれぞれの要素は、下記のようなfor文を使って繰り返し処理と組み合わせて使うと便利です。for文で宣言した繰り返し変数はfor文のブロック内で利用でき、ブロック内の命令を処理するたびに繰り返し変数が更新されます。また、毎回のブロックを処理する前には繰り返し条件が判定され、条件が成立しない場合には繰り返しが終了します。

for (<変数の宣言>; <繰り返し条件>; <変数の更新>) {
    <命令>
}

多くの場合、for文は次のような形式で書きます。これは指定した繰り返し回数だけ処理を繰り返します。このとき、変数iに記憶させる値は、順に0, 1, …, (繰り返し回数 – 1)です。

for (int i = 0; i < (繰り返し回数); i++) {
    <命令>
}

この繰り返しを配列と組み合わせると、配列に記憶させた要素を順番に取り出して処理できます。配列の長さにかかわらず同じ書き方ができるので、データの列に対して柔軟に処理を行えます。

int[] values = getValues();
int total = 0;
for (int i = 0; i < values.length; i++) {
    total = total + values[i];
}

複合データ

「複合データ」の回では、複数のデータを組み合わせた複合データをプログラムで利用するために、「クラス」と「インスタンス」について紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class Quiz {

    public static void main(String[] args) {
        new Quiz().start();
    }

    void start() {
        Question question = new Question();
        question.statement = "10 + 20 = ?";
        question.correct = 30;
        String input = JOptionPane.showInputDialog(question.statement);
        int answer = Integer.parseInt(input);
        if (answer == question.correct) {
            JOptionPane.showMessageDialog(null, "正解です");
        }
        else {
            JOptionPane.showMessageDialog(null, "不正解です");
        }
    }
}

class Question {
    String statement;
    int correct;
}

クラスはプログラムの末尾に次のような形式で宣言します。

class <クラスの名前> {
    <フィールドの宣言>
}

クラスは複合データがどのようなデータの組合せであるかという「形式」を表すもので、組み合わせるデータはフィールドとして宣言します。

<フィールドの型> <フィールドの名前>;

クラスはあくまで形式であり、プログラムから使える具体的なデータではありません。複合データをプログラムから利用するには、クラスからその具体例である「インスタンス」を生成して使います。生成したインスタンスを変数に記憶させる場合には、クラスと同じ名前の型で変数を宣言します。

<クラスの名前> <変数の名前> = new <クラスの名前>();

クラスからインスタンスを生成したら、それぞれのフィールドに値を代入します。また、同じ形式でフィールドを参照することもできます。

<変数の名前>.<フィールドの名前>

生成したインスタンスを配列に記憶させることもできます。配列は整数(int)や実数(double)、文字列(String)などのほかに、クラスと同じ名前の型を要素の型の指定できます。クラスと同じ名前の型を指定した場合、その配列に記憶させられるのは同じクラスのインスタンスです。

<要素の型>[] <変数の名前> = new <要素の型>[<配列の大きさ>];

対話型プログラム

「対話型プログラム」の回では、コンピューターと人間が対話しながら処理を進めるプログラムについて紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class LoopSum {

    public static void main(String[] args) {
        new LoopSum().start();
    }

    void start() {
        int total = 0;
        while (true) {
            int value = getInput();
            if (value == 0) {
                break;
            }
            total = total + value;
            JOptionPane.showMessageDialog(null, value +
                "が加算されました。これまでの合計は" + total);
        }
        JOptionPane.showMessageDialog(null, "終了しました。これまでの合計は" + total);
    }

    int getInput() {
        String input = JOptionPane.showInputDialog("整数を入力してください(0で終了)");
        int value = Integer.parseInt(input);
        return value;
    }
}

対話型プログラムの書き方の1つとして、無限ループと繰り返しの打切りについて紹介しました。これは下記のように無限に処理を繰り返す中で、特定の入力が行われたら繰り返しを終了させるものです。

while (true) {
    <入力の命令>
    if (<特定の値が入力されたか?>) {
        break;
    }
    <入力を利用した処理>
}
<対話を終了させる際の処理>

上記は一例で、整数以外の値を入力してもかまいません。繰り返し回数を設定せずに、プログラムを使う人が必要に応じてプログラムを終了させられることが重要です。このため、全体の繰り返しは「while (true) {…}」という形式で無限ループにしておき、特定の値が入力されたら「break;」という命令でその無限ループを終了させます。

他のパターンとして、「正しい値が入力されるまで何度も入力させる」というプログラムについても紹介しました。

while (true) {
    <入力の命令>
    if (<正しい値が入力されたか?>) {
        return <入力された値>;
    }
    <正しい値を入力させるためのメッセージ>
}

これにも無限ループの「while (true) {…}」という形式が使われていますが、繰り返しを終了させるために「break;」ではなくメソッドを終了させるreturn文を使用しています。正しい値が入力されたらreturn文でメソッドを終了させますが、そうでない値が入力された際にはメッセージが表示され、もう一度繰り返しの先頭に戻って値を入力しなおします。

参照と実体

「参照と実体」の回では、配列やインスタンスの構造や、「副作用」と呼ばれる考え方について紹介しました。

package j1.review03;

import javax.swing.JOptionPane;

public class ModifyArray {

    public static void main(String[] args) {
        new ModifyArray().start();
    }

    void start() {
        int[] array = new int[3];
        array[0] = 0;
        array[1] = 1;
        array[2] = 2;
        modify(array);
        for (int i = 0; i < array.length; i++) {
            JOptionPane.showMessageDialog(null, i + ": " + array[i]);
        }
    }

    void modify(int[] param) {
        param[1] = 12345;
    }
}

Javaには「値」と「参照」という2つの概念があり、整数や実数などは「値」として変数に記憶させていて、配列やインスタンスなどは「参照」として変数に記憶させています。そして配列やインスタンスなどの「実体」はコンピューター上の別の場所に作成され、参照によっていつでも取り出してプログラムから使用できます。

配列の場合、「int[] array = new int[3];」というような命令が処理された際に、配列の実体がコンピューター上に作成されます。ただし、変数arrayに記憶させるものは配列そのものではなく作成した配列の実体への参照です。

図: 配列の構造

インスタンスの場合も同様に、「Person instance = new Person();」というような命令が処理された際に、Personインスタンスの実体がコンピューター上に作成されます。そして変数instanceには作成した実体への参照を記憶させています。

図: クラスインスタンスの構造

メソッドを起動する際に実引数に配列やインスタンスを渡すと、それぞれの参照だけをコピーして渡します。このとき実体についてはコピーせず同じものを使用するため、起動したメソッド内で渡された配列やインスタンスを変更すると、起動元のメソッドで使っていた配列やインスタンスも変更されたことになります。

図: 配列の変更

また、複雑な参照の例として2次元配列についても紹介しました。2次元配列は2つのインデックスを指定して要素を指定する配列で、次のように作成します。

<要素の型>[][] <変数の名前> = <要素の型>[<1次元目の要素数>][<2次元目の要素数>];

2次元配列の要素を参照するには、次のようにインデックスを2回指定します。

<変数の名前>[<1次元目のインデックス>][<2次元目のインデックス>]

これは、次のように2重になった参照と実体を順番にたどっていくような形で処理されます。

図: 2次元配列の構造

このような2次元配列の要素を利用する場合には、次のように2重になったfor文が便利です。外側の繰り返し(変数i)で1次元目を反復し、内側の繰り返し(変数j)で2次元目を反復しています。

for (int i = 0; i < <1次元目の要素数>; i++) {
    for (int j = 0; j < <2次元目の要素数>; j++) {
        … <変数の名前>[i][j] …
    }
}

達成度の確認

以下それぞれの項目は、コース全体を通して紹介してきた個々の内容です。漏れが無いか確認し、必要に応じて過去の資料を見直してください。