BlueJの使い方~インストール、クラス作成、サンプルプロジェクト~

BlueJの使い方

Oracle製のIDE「BlueJ」を使ってみようと思います。
そもそも、「なんで使ってみようと思ったのか?」に関して、以下の理由があります。
下の動画のように、作成したクラスがクラス図(簡易バージョン)で表現されるところです。
<HelloWorldの実行動画>

他にも、継承関係も表示できる用ですので、クラス間の関係性を説明するときに、自分で確認するときにも便利です。

ライブラリの追加

スタックオーバーフローより
「Tools -> Preferences -> Libraries -> Add file」ということで。

「ツール→カスタマイズ→ライブラリタブ」を開いて、Jarファイルを追加、BlueJを再起動することで使用可能になるようです。

BlueJインストール

こちらのページからダウンロードできます。MSIファイルなので、クリックするだけでインストールできました。

そして、ドキュメント、サンプルプロジェクトもそろっているようです。

そんなわけで、上記の赤丸部分をクリックしてダウンロードした。ファイルの中身を見てみます。

注意点

コンパイルするときには、修正したクラスを全て、コンパイルする必要があります。

サンプルプロジェクト

ダウンロードしたprojects.zipを展開すると、Chapter01~16までプロジェクトが入っていました。
これらの中にあるフォルダが、BlueJで開くべきプロジェクトになります。

Chapter1のプロジェクト(figure)

開いたプロジェクトは下のような形でした。

これに、メインクラスを作成し、メインメソッドを追加して実行しました。

<実行結果>

サンプルプロジェクトを見る

ダウンロードしたZIPファイルを展開したあと、「projects」-> 「chapter01」-> プロジェクトとフォルダを下がっていく形になります。
具体的には、「projects」-> 「chapter01」-> 「home」を開きます。

プロジェクトを開いた結果

ここから、Javaプログラムの解説になります。

Java プログラム

開いたプロジェクトは、下のようなクラスがあります。

  • Picture
  • Circle
  • Square
  • Triangle
  • Person
  • Canvas

クラスの関係について

上記のクラス図から、Circle, Square, Triangleの3クラスがPictureクラスに呼び出されています。

そして、Picture以外のクラスがCanvasクラスを呼び出しています。

なので、ここに「」クラスを作成し、Picture、Personクラスを起動するメインメソッドを実装、起動します。

Pictureクラス

このクラスは、Circle, Square, Triangleの3クラスを呼び出しています。
詳細は、フィールド変数に上記の3クラスを持っています。
そして、コンストラクタで各クラスのインスタンス化を行い。
draw()メソッドで描画を行っています。

なので、メインメソッドでは、インスタンス化とdraw()を呼び出しを行っています。

/**
 * This class represents a simple picture. You can draw the picture using
 * the draw method. But wait, there's more: being an electronic picture, it
 * can be changed. You can set it to black-and-white display and back to
 * colors (only after it's been drawn, of course).
 *
 * This class was written as an early example for teaching Java with BlueJ.
 * 
 * @author  Michael Kölling and David J. Barnes
 * @version 2016.02.29
 */
public class Picture
{
    private Square wall;
    private Square window;
    private Triangle roof;
    private Circle sun;
    private boolean drawn;

    /**
     * Constructor for objects of class Picture
     */
    public Picture()
    {
        wall = new Square();
        window = new Square();
        roof = new Triangle();
        sun = new Circle();
        drawn = false;
    }

    /**
     * Draw this picture.
     */
    public void draw()
    {
        if(!drawn) {
            wall.moveHorizontal(-140);
            wall.moveVertical(20);
            wall.changeSize(120);
            wall.makeVisible();

            window.changeColor("black");
            window.moveHorizontal(-120);
            window.moveVertical(40);
            window.changeSize(40);
            window.makeVisible();

            roof.changeSize(60, 180);
            roof.moveHorizontal(20);
            roof.moveVertical(-60);
            roof.makeVisible();

            sun.changeColor("yellow");
            sun.moveHorizontal(100);
            sun.moveVertical(-40);
            sun.changeSize(80);
            sun.makeVisible();
            drawn = true;
        }
    }

    /**
     * Change this picture to black/white display
     */
    public void setBlackAndWhite()
    {
        wall.changeColor("black");
        window.changeColor("white");
        roof.changeColor("black");
        sun.changeColor("black");
    }

    /**
     * Change this picture to use color display
     */
    public void setColor()
    {
        wall.changeColor("red");
        window.changeColor("black");
        roof.changeColor("green");
        sun.changeColor("yellow");
    }
}

Mainクラス

このクラスは、筆者が作成したクラスです。単純にPictureクラスとPersonクラスをインスタンス化してそれぞれ描画するメソッドを起動しています。

public class Main
{
  public static void main(String[] args) {
      Picture pic = new Picture();
      Person per = new Person();

      pic.draw();
      per.makeVisible();
  }
}

Extension(拡張)

拡張機能に関して、こちらの記事にありました。

BlueJはSwingを使用して作成されているのか。。。拡張するのにSwingを使用して拡張するようです。

次の例では、ユーザーが開いたすべての BlueJ プロジェクトの名前をログに記録する拡張機能を実装しSystem.out 、他の拡張機能の使用方法を示します。インストールすると、次のようにも表示されます。

  • BlueJ ヘルプメニューの「Installed Extensions」パネルにあるエントリ
  • (あまり役に立たない) BlueJ の [ツール] メニューへのメニュー エントリ、および既存のクラスのソース コードにコメントを追加するものを含む、クラスおよびオブジェクト用に表示されるメニューへのエントリ。
  • Tools/Preferences/Extensions パネルのエントリで、お気に入りの色を入力 (および保存) します。
    拡張機能の完全なソース コードはこちらです。

単体テスト

こちらにあるドキュメントを見るとやり方が書いてあるのですが、ちょっと違うようで。。。

テストクラスを作成する

下の図のように、対象クラスを右クリックします。そして、「テストクラスの作成」を選択します。

すると、下のようなクラスが作成されます。
対象にしているクラスはXMLUtilクラスです。

作成したクラスは、下のように表示されます。

Java Basic 総復習編 〜基本と基本文法編〜

Java Basic 総復習

今まで、Javaを学習してきて、なんとなくはわかったけどクラスとかオブジェクトという言葉が出てきたら頭がこんがらがってきた。という事象があるかと思います。

<プログラミングのチュートリアル(説明)動画>

自分も昔そうでした。。。そうだったような気がします。

それならば、整理すれば良いのです。簡単な話です。

復習内容リスト

  1. プログラムの流れ
  2. 変数の扱い
  3. 式と演算子
  4. if文
  5. switch文
  6. while文
  7. for文

プログラムの流れ

まずは、プログラムの流れについて復習します。クラスやメソッドなどが出てきて処理があちこちに飛ぶように感じられると思いますが、そんなことはありません。順序立てて動いています。

まずは、メインメソッドが動く

どのクラスにも作成することができますが、1つのアプリケーションとして動かすときは、「必ずメインメソッドが動く」ということを忘れないでください。

例えば、下のようなコードがあったとします。

public class First {
 public static void main(String[] args) {
       System.out.println("Hello World");
       First main = new First();
       main.hello();
   }
   public void hello() {
       System.out.println("Second Hello World");
   }
}

この時に、メインメソッドの中では、クラスをnewしてやらないとメンバメソッド(インスタンスメソッド)は起動できません。
それは、「static」がついているメソッドは、特別なメソッドなので、インスタンスメソッドと区別されます。

ここでの、処理の順番は、以下のようになります。

  1. メインメソッドが動く
  2. 「Hello World」をコンソールに出力
  3. Firstクラスをインスタンス化
  4. インスタンスメソッドの「hello()」を呼び出す

このように動きます。ここでの注意ポイントは「First」クラス型の変数「main」です。

変数の扱い

変数はプログラムを動かすために必要になるものですが、あまり細かいところまで解説をすることが少ないです。
実際に、覚えることはint型は「整数」とか、「double」型は少数。。。
というように、データ型の用途に対する説明のみになってしまうからです。

変数には「プリミティブ型」と「参照型(クラス型)」がありますが、参照型に関しては自作クラスも参照型として分類されるので
プリミティブ型のように「これは整数型です」というような言い方ができません。

ただし、String型はクラス型です。他にも、int型を参照型にしたものがあります。それぞれ下のようになっています。
<プリミティブ型 -> 参照型>

  • int -> Integerクラス
  • double -> Doubleクラス
  • boolean -> Booleanクラス
  • long -> Longクラス
  • float -> Floatクラス

<リテラルに関する解説>

変数の定義方法は全て同じ

今までよく目にしている、下のような変数の宣言は理解できていると思います。

int num = 0;
String str = "はじめの一歩";

変数の宣言・初期化は必ず「データ型 変数名 = 代入する値」という形で行います。

これは変数のデータ型がどんなものになっても変わりません。

<変数の扱い方>

データ型とは

以下のものがあります。

  1. int, double, float, lognなどのプリミティブ型と呼ばれる(分類される)変数の型
  2. String, 配列(int[], double[], String[], クラス名[])などの参照型と呼ばれる(分類される)変数の型

例. 変数宣言(初期化)

int num = 0;
String str = "はじめの一歩";
First main = new  FIrst();
List<String> list = new ArrayList<String>();
Scanner scan = new Scanner(System.in);
Random rnd = new Random();

上から順に

  1. int型の変数numを0で初期化
  2. 文字列型(String型)の変数strを"はじめの一歩”で初期化
  3. First型の変数mainをFirstクラスのインスタンスを生成して初期化
  4. List\<String>型の変数listをArrayList\<String>クラスをインスタンス化して代入
  5. Scanner型の変数scanにScannerクラスをインスタンス化して代入
  6. Random型の変数rndにRandomクラスをインスタンス化して代入

式と演算子

演算子には以下のようなものがあります。
算術演算子:「+」 「-」 「*」 「/」 「%」 「^」 「++」 「--」
比較演算子:「==」 「!=」 「「<」 「>」 「<=」 「>=」
論理演算子:「&&」 「||」

そのほかの演算子
instanceof」:クラス型の比較を行います。

String st = "aa";
if (st instanceof String) {
    System.out.println("同じString型です。");
}

代入演算子:「=」値を代入します。

int num = 0; // int型の変数に0を代入
First first = new First(); // First型の変数firstにFirstクラスのインスタンスを代入
String st = "aaa"; // String型の変数stに文字列「aaa」を代入

ここで注意して欲しいのが、「1」と「"」がついていないもの、リテラル(値)は「数値」として扱われる
逆に「"」で囲われているもの、リテラル(値)は文字列としてある変われる

この「=」が、いまいち、ピンとこない人に向けて例を以下に書きます。

public static void main(String[] args) {
    String st = getString();
}
public static String getString() {
     return "String";
}

上のコードは、クラスを省略して書いていますが、メインメソッドから「getString()」というメソッドを呼び出します。
この「getString()」は返り値(戻り値)にString型(文字列型)を定義しています。

なので、「getString()」のメソッドを呼び出したらString型の値を受け取ることができます。

これに対して、クラスをnewして実行した時に関しても同じです。ちょっと長いですが。。。

public class Sample {
    /** フィールド変数 */
    private int field_int = 0;
    private String field_String = "もじれつ";
    //////// 注意(教科書の書き方はほぼ使わない) /////
    // String package_String = "使わない";

    public static void main(String[] args) {
        // Sampleクラス型の変数mainにSampleクラスをインスタンス化して代入
        Sample main = new Sample();
        // 返り値(戻り値)が「void」の場合は変数を受け取る必要がない
        main.hello();
        staticHello();

        // 返り値(戻り値)が定義されている場合(voidになっていない場合)
        // 返り値(戻り値)を受け取ることができる
        Sring result = getString();
        System.out.println("getString()の戻り値は" + result);
    }

    public static void staticHello() {
        System.out.println("Hello World");
    }
    /**
     * <コンストラクタの書き方>
     * アクセス修飾子 クラス名(引数) { ... }
     *
     * newした時の処理を書く
     */
    public Sample() {
        this.field_int = 5;
        this.field_String = "aaaa時の値";
    }

    /**
     * コンストラクタのオーバーロード
     * @param num
     * @param str
     */
    public Sample(int num, String str) {
        this.field_int = num;
        this.field_String = str;
    }

    /**
     * ハローメソッド
     */
    public void hello() {
        System.out.println(this.field_String);
        this.hello("こんにちは、フィールド変数:" + this.field_int);
        this.hello2();
    }
    /**
     * ハローメソッド
     */
    public void hello2() {
        System.out.println(this.field_String);
        this.hello("こんにちは、フィールド変数:" + this.field_int);
        String st = "aa";
        String gg = "ss";
        if (st instanceof String) {
            System.out.println("同じString型です。");
        }
    }

    public String getString() {
        return "String";
    }
}

上記のコードのうち戻り値が「void」のものは以下になります。

  • helllo()
  • hello2()
  • staticHello()

そして。返却値(戻り値)の指定があるもの(voidではないもの)は以下の通りです。

  • getString()

このgetString()メソッドはString型の値を返しますので、呼び出し元(メインメソッド)ではString型の変数resultで受け取っています。
当然受け取らなくても良いので、下のように書いてもエラーは出ません。

getString();

上記の場合は、String型の値を受け取っても、変数に代入していないのでメインメソッドでは使用することができません。
使用する必要がなければ、このようなメソッドの呼び出しもOKです。

if文

条件分岐処理の構文です。

if (論理式) {
   // trueの場合の処理
} else {
  // falseの場合の処理
}

実際に使用するときは下のように書く

String st = "aa";
if (st instanceof String) {
    System.out.println("同じString型です。");
}
if ("aa".equals(st)) {
    System.out.println("stはaaです。");
} else if ("bb".equals(st) ) {
    System.out.println("stはbbです。");
} else {
    System.out.println("stはその他の値です。");
}

それぞれif (論理式) { ... }の「論理式」の部分で値が「true / false」が帰ってきたところで処理の流れが変わります。

論理式

返り値としてbooleanが返される式のことです。以下の指揮がそれにあたります。

boolean isTrue = "aaa".equals("aaa");
boolean isFalse = "aAb".equals("aaa");
isTrue = 1 == 1;
isFalse = 2 == 1;
isTrue = 1 < 2;
isFalse = 1 != 2;

「返る」というのは「=」の反対側に値を渡すという意味です。

switch文

上記のif文と同じ処理がかけます。下のようになります。

switch(st) {
case "aa": 
    System.out.println("stはaaです。");
    break;
case "bb":
    System.out.println("stはbbです。");
    break;
default:
    System.out.println("stはその他の値です。");
}

while文

繰り返し処理の最もシンプルなものです。
下のように論理式の結果が「true」の間繰り返し処理を行います。

int num = 0;
while (num < 10) {
     System.out.println("num = " + num);
     num++;
}

上のコードは「num = 0」〜「num = 9」までを表示します。

for文

繰り返し処理の最もおポピュラーなものです。

for (int i = 0; i < 10; i++) {
     System.out.println("num = " + num);
}

上のコードは「num = 0」〜「num = 9」までを表示します。

大まかに基本文法と変数の扱い方などを記載しました。

Java を支えるクラスたちに目を向ける 〜Java API〜

イントロダクション

今まで、Javaを学習してきて、何気なく使用していたクラスがあります。

気づかいない間に使用しているものもあります。これらはjava.langパッケージに入っているクラス群で、importしなくても使用することができます。

その代表的なクラス(Java API)がStringクラス(文字列)です。

Java を支えるクラスたち

Java APIというとJava言語自体のことを指すのですが、解釈のしかたは人によって違うようです。

しかし、はっきりしているのは「Java言語で使用するクラス群のこと」だということです。

Stringクラスを使う

まずは、プログラムをガンガン実行するための準備をします。

<==プロジェクトの作成とJUnitの設定==>

そうすると、JUnitが使用できるようになります。

==JUnitを使った動画(再生リスト)==

<ミッション1>
以下のクラスを作成して、実行した結果が想定通りになることを確認してください。

手順

  1. 以下の「作成するパッケージ」を作成する
  2. 同様に「作成するクラス」を作成する
  3. 同様に「A. テストケースの作成」を作成する
  4. 同様に「B. 作成するクラスのフィールド」を作成する
  5. 同様に「C. 作成するメソッド」を作成する

== 作成するパッケージ ==
practice.自分の名前.util

==作成するクラス==
srcフォルダに、StringUtilsクラスを作成
testフォルダに、StringUtilsTestクラスを作成

==A. テストケースの作成==
以下の処理を確認するテストケースを作成します。

⑴ 2つの引数がどちらも空(から)文字("")、もしくは null の場合、定数EMPTY「0」を返す(retunする)
⑵ 2つの引数が等しい場合、定数EQUAL「1」を返す(returnする)
⑶ 2つの引数が、大文字小文字の区別をしないで、等しい場合、定数IGNORE「2」を返す(returnする)

<テストケース(メソッド)の書き方>

@Test
public void testStringUtils01() {
    StringUtils target = new StringUtils();
    // 作成するメソッドの<処理>の1の内容を確認する処理
    // assertEquals(想定する結果の値, 検証する値);
   assertEquals(StringUtils.EMPTY,  target.stringTest01("", null));
}

*上の例に習い、2、3の処理を確認する処理を作成しましょう。

==B. 作成するクラスのフィールド==

  1. 定数EMPTYを整数型「0」で初期化
  2. 定数EQUALを整数型「1」で初期化
  3. 定数IGNOREを整数型「2」で初期化

==C. 作成するメソッド==

  1. 戻り値(返り値): 整数型(int型)
  2. メソッド名: stringTest1
  3. 引数リスト: 文字列型 leftStr, 文字列型 rightStr
  4. 処理内容:

 <処理>
 a. 引数にある文字列が空("")であれば、定数EMPTYを返す
 b. 引数にある文字列 leftStrとrightStrが等しいのであれば、定数 EQUALを返す
 c. 引数にある文字列が leftStrとrightStrがであれば、定数IGNOREを返す

<ミッション2>
ミッション1で作成した、StringUtilsTestクラスに、以下のテストケースを追加
・「引数に渡した文字列を大文字に変換することを確認する」
・「引数に渡した文字列を小文字に変換することを確認する」

以下、手順に従いテストケースの作成及び、クラスの作成を行う

手順

*String#toUpperCase()の実装

  1. StringUtilsクラスのconvertUpper()メソッドの引数に、
      文字列「"aaa"」を渡し、結果が「"AAA"」と等しいことを確認する

*String#toLowerCase()の実装

  1. StringUtilsクラスのconvertLower()メソッドの引数に、
      文字列「"TeStA"」を渡し、結果が「"testa"」と等しいことを確認する

*String#startWith()とendWithの実装

  1. StringUtilsクラスのstartEndWith()メソッドの引数に、
      文字列「"starts"」を渡し、結果が「true」と等しいことを確認する
  2. StringUtilsクラスのstartEndWith()メソッドの引数に、
      文字列「"start"」を渡し、結果が「false」と等しいことを確認する5. StringUtilsクラスのstartEndWith()メソッドの引数に、
      文字列「"atarts"」を渡し、結果が「false」と等しいことを確認する
  3. StringUtilsクラスのstartEndWith()メソッドの引数に、
      文字列「"strings"」を渡し、結果が「true」と等しいことを確認する

*String#IndexOf()の実装

  1. StringUtilsクラスのfindStr()メソッドの引数に、
      文字列「"Tesea"」と「"e"」を渡し、結果が「1」と等しいことを確認する
  2. StringUtilsクラスのfindStr()メソッドの引数に、
      文字列「"Tesea"」と「"T"」を渡し、結果が「0」と等しいことを確認する

*String#lastIndexOf()の実装

  1. StringUtilsクラスのfindLastStr()メソッドの引数に、
      文字列「"Takashimaya"」と「"a"」を渡し、結果が「1」と等しいことを確認する
  2. StringUtilsクラスのfindLastStr()メソッドの引数に、
      文字列「"Tesea"」と「"e"」を渡し、結果が「3」と等しいことを確認する
    11 StringUtilsクラスのfindLastStr()メソッドの引数に、
      文字列「"Takashimaya"」と「"a"」を渡し、結果が「10」と等しいことを確認する

*String#substring()の実装
12 StringUtilsクラスのsubString()メソッドの引数に、
  文字列「"abcdefg"」、整数「0」、整数「3」を渡し、結果が「abc」と等しいことを確認する
13 StringUtilsクラスのsubString()メソッドの引数に、
  文字列「"abcdefg"」、整数「3」を渡し、結果が「efg」と等しいことを確認する
14 StringUtilsクラスのsubString()メソッドの引数に、
  文字列「"abcdefg"」、整数「3」、整数「7」を渡し、結果が「defg」と等しいことを確認する

*String#trim()の実装(スペースが入っているので注意しましょう)
15 StringUtilsクラスのtrimStr()メソッドの引数に、
  文字列「" abcd "」を渡し、結果が「abcd」と等しいことを確認する
16 StringUtilsクラスのtrimStr()メソッドの引数に、
  文字列「" a bcd "」を渡し、結果が「a bcd」と等しいことを確認する

*String#replace()の実装
17 StringUtilsクラスのreplaceStr()メソッドの引数に、
  文字列「"abcd"」、文字列「”c"」、文字列「"あ"」を渡し、結果が「abあd」と等しいことを確認する
18 StringUtilsクラスのreplaceStr()メソッドの引数に、
  文字列「"abcda"」、文字列「”a"」、文字列「"C"」を渡し、結果が「abCd」と等しいことを確認する

*String#replaceAll()の実装
19 StringUtilsクラスのreplaceStr()メソッドの引数に、
  文字列「"abcda"」、文字列「”c"」、文字列「"あ"」を渡し、結果が「abあd」と等しいことを確認する
20 StringUtilsクラスのreplaceStr()メソッドの引数に、
  文字列「"abcda"」、文字列「”a"」、文字列「"あ"」を渡し、結果が「あbcdあ」と等しいことを確認する

解答例

<StringUtils.java>

public class StringUtils {
    /** 定数 */
    public static final int EMPTY = 0;
    public static final int EQUAL = 1;
    public static final int IGNORE = 2;
    public static final int ERROR = -1;

    public int stringTest01(String str1, String str2) {
        if ("".equals(str1)) {
            return EMPTY;
        }
        if ("".equals(str2)) {
            return EMPTY;
        }
        return ERROR;
    }

    public int stringUtils02(String str1, String str2) {
        int result = ERROR;
//      if (this.isEmpty(str1, str2)) {
//          return ERROR;
//      }
        if (str1.equals(str2)) {
            result = EQUAL;
        } else {
            result = ERROR;
        }
        return result;
    }

    public boolean isEmpty(String str1, String str2) {
        if (str1 == null || str2 == null) {
            return true;
        }
        if ("".equals(str1) || "".equals(str2)) {
            return true;
        }
        return false;
    }
}

< StringUtilsTest>

public class StringUtilsTest {
    @Test
    public void testStringUtils01() {
        StringUtils target = new StringUtils();
         // 作成するメソッドの<処理>の1の内容を確認する処理
        // assertEquals(想定する結果の値, 検証する値);
        assertEquals(StringUtils.EMPTY,  target.stringTest01("", null));
    }

    @Test
    public void testStringUtils02() {
        StringUtils target = new StringUtils();
        assertEquals(StringUtils.EQUAL, target.stringUtils02("aaa", "aaa"));
        assertEquals(StringUtils.ERROR, target.stringUtils02("aaa", "aab"));
        //assertEquals(StringUtils.ERROR, target.stringUtils02(null, "aab"));
        assertEquals(StringUtils.IGNORE, target.stringUtils02("aaa", "AAA"));
    }
}

クラスの扱い方の練習

問題

  1. プロジェクト「JavaExamTrain」を作成してください、すでにプロジェクトが存在する場合は何もしなくて良いです。
  2. 以下のパッケージを作成してください
    ・ practice.exam.mondai
    ・ practice.exam.mondai.logic
  3. 同様に、添付のファイルをダウンロードもしくはコピーしてソースフォルダ「resources」に「sample.csv」を作成してください、またresourcesフォルダにビルドパスを通してください。
  4. 以下のクラスを作成してください
    ・practice.exam.mondai.MondaiMain
    ・practice.exam.mondai.logic.ExamLogic
  5. ExamLogicクラスに、以下のような実装をしてください。
    ・返り値(戻り値):なし、メソッド名:printMessage、引数:なし
    ・String型の配列hako を文字列「50」「sy」「s_」「jo」「5f」「3d」「es」で初期化してください。
    ・int型の配列hintを数値「3」「1」「2」「4」「0」「5」「6」で初期化してください。
    ・拡張for文を使って、変数hintの値に対応する番号(添え字)の、変数hakoの文字列を標準出力に出力してください。
  6. ExamLogicクラスに、以下のようなコンストラクタを実装をしてください。
    ・引数なし
    ・String型のフィールド変数nameに文字列「タイガー」を代入する
    ・int型のフィールド変数ageに数値「19」を代入する
    ・ExamSwordクラス型のフィールド変数swordにExamSwordクラスのインスタンスを代入する
    ※ExamSwordクラスはMondaiLogicクラスと同じパッケージに作成する
  7. ExamLogicクラスに、以下のようなコンストラクタを実装をしてください。
    ・引数:文字列
    ・String型のフィールド変数nameに文字列引数の文字列を代入する
    ・int型のフィールド変数ageに数値「19」を代入する
    ・ExamSwordクラス型のフィールド変数swordにExamSwordクラスのインスタンスを代入する
    ※ExamSwordクラスはMondaiLogicクラスと同じパッケージに作成する
    ・次のような文字列を表示してください。「[name]」「[age]」はそれぞれフィールド変数を示すものとする
    「私の名前は[name]です。[age]才です。エモノは[ExamSword#name]です。」
    ※[ExamSword#name]はExamSwordクラスのフィールド変数nameを示すものとする。
  8. MondaiMainクラスに以下のような実装をしてください。
    ・ExamLogic型のフィールド変数logicを作成してください。
    ・コンストラクタでフィールド変数logicにExamLogicのインスタンスを代入してください。
    ・メインメソッドで、logicクラスのインスタンス・メソッド「printMessage」を呼び出してください。

Java 例外の処理方法 〜try catchの使い方とFile入出力〜

イントロダクション

前回は、ポリモーフィズムの実装を行いました。

これは、クラスの継承関係を作り、クラスの型をうまく変換して多様な使い方を行うというものでした。

例えば、下のような使い方をしました。

勇者率いるパーティを表現

public static void main(String[] args) {
        Character[] party = new Character[2];
        party[0] = new Hero("太郎");
        party[1] = new Wizard("二郎");

        System.out.println("こんにちは、良いパーティですね。");
        for (int i = 0; i < party.length; i++) {
            // ここの処理を変更する必要がある
            System.out.println(party[i].getName() + "さん");
        }
}

この実装は、下の図のように、クラスの継承関係作り、Hero, Wizardのクラスを1つのデータ型( クラス型)として使用しています。

Javaプログラムは「型安全」なので、データ型は厳密です。

しかし、このような形でクラスの継承関係を作ると、いろんな組み合わせが可能になります。

このような実装のことを「ポリモーフィズム」と言いました。

例外処理

何かと倦厭されがちな「例外処理」ですが、上のポリモーフィズムの実装は単純なので例外処理がなくても問題ありませんが、これに対して、複雑な組み合わせを行った時、例外処理がないととても不便なのです。

==エラーの種類==

  1. 文法エラー
  2. 実行時エラー
  3. 論理エラー(仮にこう呼ぶ):処理の結果が想定通りでない。

そして、上のようなエラーがあったときにそれぞれの例外を投げます。これは、プログラムの文法で「Throw」という文言を使用するためです。日本語では「投げる」です。

例えば、例外の処理は以下の系統に分けることができます。

  • Error: 通常のアプリケーションであればキャッチすべきではない重大な問題
  • Exception: 通常のアプリケーションでキャッチされる可能性のある状態、クラスExceptionと、そのサブクラスのうちでRuntimeExceptionのサブクラスでないものがすべて、チェック例外になります。
  • RuntimeException: Java仮想マシンの通常の処理でスローすることができる各種の例外のスーパー・クラスです。

エラーがどこで起きたか分からない

稀に、例外が出てもエラーメッセージを見ない人がいますが、ちゃんと見ましょう。「どこでエラーが出ているのか?」はこの例外処理の結果を見ればわかるはずです。

そのように作れば良いのです。

File入出力

例外処理の代表的なものは「ファイル入出力」です。このファイル操作の処理を実装するときに必ず「IOException」が出てきます。ただし、ラップしているような処理は見えてきませんが。。。

そんなわけで、File入出力の実装をして見ましょう。

<プロパティファイルを読み込む(全部)>

private void loadProperties(String fileName) {
    Properties prop = new Properties();
    try {
        Path path = Paths.get("resources", fileName);

        if (isDebug) System.out.println("Path: " + path.getParent().toString() + "\\" + fileName);

        BufferedReader buf = Files.newBufferedReader(path);
        prop.load(buf);
    } catch (IOException ie) {
        System.out.println(fileName + "の読み込み時にエラーがありました。");
        ie.printStackTrace();
        System.exit(-1);
    }
    if (isDebug) System.out.println("propLength: " + prop.size());

    prop.keySet().stream().forEach(key-> {
        // key = 実行クラスの番号
        String className = prop.getProperty(key.toString());
        try {
            Class<CommandIF> klass = (Class<CommandIF>) Class.forName(className);
            clsMap.put(key.toString(), klass);
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(-1);
        }
    });

    if (clsMap.size() == 0) {
        System.out.println("プロパティファイルにクラスが登録されていません。");
        System.exit(-1);
    }
}

この処理で、プロパティファイルに書いてある、キーから完全クラス名を取得し、クラス・オブジェクトを取得、Mapインターフェースに登録しています。

細かく見ていきますので、ご安心ください

ファイルの読み込み

ファイルの読み込み処理の部分です。以下に抜粋します。

    Properties prop = new Properties();
    try {
        Path path = Paths.get("resources", fileName);

        if (isDebug) System.out.println("Path: " + path.getParent().toString() + "\\" + fileName);

        BufferedReader buf = Files.newBufferedReader(path);
        prop.load(buf);
    } catch (IOException ie) {
        System.out.println(fileName + "の読み込み時にエラーがありました。");
        ie.printStackTrace();
        System.exit(-1);
    }

この部分はfileNameに文字列で「ファイル名」が入っている想定です。

想定というのは、そのようにメソッドを使ってもらう前提ということです。

そして、上から順に、

Properties prop = new Properties();

ここで、プロパティクラスをインスタンス化しています。

Path path = Paths.get("resources", fileName);

この行では、resourceフォルダ内にある「fileName」のパスを取得しています。*ファイルがないときはnullが返ります。

下の処理はデバック用の処理です。取得したパスを文字列で表示しています。

if (isDebug) System.out.println("Path: " + path.getParent().toString() + "\\" + fileName);

そして、ファイルを読み込むためのクラスを取得(インスタンス化)します。

BufferedReader buf = Files.newBufferedReader(path);

最後に、Propetiesクラスで、取得したファイルリーダー(クラス)からプロパティファイルをロードします。

お気付きの方がいるかもしれませんが、ここで読み込もうとしているのは、プロパティファイルです。

ここまでが、処理の説明になります。

例が処理について

例外処理に関しては、try { ... } catch (例外クラス) { ... }で囲まれた、処理を書きます。

具体的には、このように書きます。

    try {
        Path path = Paths.get("resources", fileName);

        if (isDebug) System.out.println("Path: " + path.getParent().toString() + "\\" + fileName);

        BufferedReader buf = Files.newBufferedReader(path);
        prop.load(buf);
    } catch (IOException ie) {
        System.out.println(fileName + "の読み込み時にエラーがありました。");
        ie.printStackTrace();
        // プログラムの強制終了
        System.exit(-1);
    }

このように、ファイルを読み込もうとしたときに、例外が発生する可能性があるので、下のコードはThrows文が書かれています。
<使用している部分>

BufferedReader buf = Files.newBufferedReader(path);

<呼び出しているメソッドの定義>

BufferedReader java.nio.file.Files.newBufferedReader(Path path) throws IOException

なので、throwをキャッチする処理を書かなくてはなりません。

このように、例外が発生する可能性があるのであれば、「throws」文を使い例外が発生する可能性があることを呼び出した側のメソッドに通知する必要があります。

逆にメソッドの内部で揉み消してしまうならば、下のようにtry-catchで処理をしてしまえば良いのです。

    try {
        // 何かしらの処理
    } catch (IOException ie) {
        System.out.println("エラーがありました。");
        ie.printStackTrace();
        // プログラムの強制終了
        System.exit(-1);
    }

実際に作ってみる

まずは、サンプルコードを見てください。実行確認済みです。

public static void main(String[] args) {
    Path path = Paths.get("resources", "mains.properties");
    try {
        BufferedReader read = Files.newBufferedReader(path);
        String line = null;
        while((line = read.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException ie) {
        ie.printStackTrace();
        System.exit(-1);
    }
}

メインメソッドで、ファイル読み込みの処理を行ったものです。

<処理内容>

  1. resourceフォルダ(ビルドパスが通っている)にある「mains.properties」のパスを取得します。
  2. ファイル読み込みクラス、BufferedReaderを作成(インスタンス化)します。
  3. ファイルの内容を1行ずつ、読み込み、読み込み行がないならばnullが返ってくるので処理を終了します。
     ファイルの内容を標準出力に出力している

このような形で、例外処理を行いますが、これを別なkたちで使用することもあります。

チェック時の例外を投げる

<入力チェックの例外>
【前提】
・CheckerUtils#fixStr()は以下のように定義している

public static boolean fixStr(String str) throws Exception {
    if (str == null) {
        throw new Exception("strはnullにできません");
    }
    System.out.println(str);
}

<呼び出し元>

public static void main(String[] arg) {
    try {
        ChecherUtis.fixStr("aaaa");
    } catch (Exception e) {
        e.printStackTrace();
        Systme.exit(-1);
    }
}

このようにすると、例外に「strはnullにできません」と表示することができます。

さらに、Exceptionクラスを拡張して、下のように、自前の例外を作成することも可能です。

public class HeroExceptiion extends Exception {
    public HeroExceptiion(String message) {
        super(message);
    }
}

結局のところは、例外クラスの名前が変わるだけなのですが、この例外が出るところは決まってくるので。デバック時も問題になりません。

結構便利です。

今回はこんなところで。。。

でわでわ。。。

継承に関するページ一覧

  1. Java オブジェクト指向基礎 ~オブジェクト指向コンセプト~
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. Java クラスの継承を理解する
  4. クラスの継承〜アクセス修飾子〜
  5. クラスの継承関係を作る1
  6. クラスの継承関係を作る2

環境構築関連ページ一覧

設計関連ページ一覧

  1. 設計を始める〜1.アプリイメージ〜
  2. 設計を始める〜2.機能イメージ〜
  3. 設計を始める〜3.機能概要〜
  4. Java はじめて16 〜クラス設計から実装〜

PHP関連ページ

  1. WordPress プラグイン作成〜DBを使用する〜
  2. PHP PDO 〜MySQLにアクセスする〜
  3. PHP Ajax 〜DBに登録したデータを受信する〜
  4. Google Maps API PHP連携 〜マップ情報をDBに登録する〜
  5. PHP Image File 〜iPhoneやAndroidでの画像送受信の問題〜
  6. AngularJS Routing 〜PHPをWeb APIにする〜
  7. WordPress PHPカスタム〜根本的に見た目を変える〜
  8. WordPress PHPカスタム〜根本的に見た目を変える2〜
  9. Eclipse PHPプラグイン 〜ElipseでWordPress環境を構築〜
  10. WordPress テスト実装 〜heade-test.phpを表示〜
  11. AngularJS + PHP 〜WordPressと連携する〜
  12. AngularJS + PHP 〜AngularJSの実装〜
  13. AngularJS + PHP 〜AngularJSの実装2〜
  14. WordPress 処理解析 ~index.phpを眺める~
  15. WordPress Plugin NewStatPress ~アクセス解析プラグインAPIを使う~
  16. WordPress 処理解析 ~ログイン処理を調べる~
  17. WordPressカスタム〜アンケートボタンを追加する(設計)〜
  18. WordPressカスタム〜プラグインの作成〜
  19. WordPressカスタム〜ダッシュボードのプラグイン画面作成〜
  20. WordPressカスタム〜ダッシュボードのプラグイン画面作成2〜
  21. WordPressカスタム〜ダッシュボードのプラグイン画面作成3〜
  22. WordPress プラグイン作成〜アンケート作成プラグインを作る〜

JS関連ページ

  1. JS GoogleMaps API 〜オリジナル・データマップを作ろう〜
  2. 吹き出しにYoubetubeを埋め込む
  3. Ajax + XmlHttpRequest〜画像送信からDB登録して表示〜
  4. JS XmlHttpRequest 〜JSでの同期/非同期通信〜
  5. JS Google Maps API 〜GeoLocation 現在位置の取得〜
  6. AngularJS + PHP 〜AngularJSの実装〜
  7. AngularJS + PHP 〜AngularJSの実装2〜
  8. WordPress プラグイン作成 〜$wpdbでのSELECT〜
  9. WordPressプラグイン作成 〜HTML挿入まで完了〜
  10. WordPress プラグイン作成 〜アンケート挿入〜
  11. MAMP 起動設定 〜WordPressのテスト環境を作る〜
  12. MAMP WordPress 〜インポート時のエラー対処〜
  13. WordPress PHPカスタム〜根本的に見た目を変える2〜

数理モデル関連ページ

  1. 数学への挑戦 第二弾〜数理モデルxプログラミング〜
  2. 数学への挑戦 第二弾〜実装編:数理モデルxプログラミング〜
  3. 数学への挑戦 第二弾〜集合を使う:数理モデルxプログラミング〜
  4. 数学への挑戦 第二弾〜確率変数:数理モデルxプログラミング〜
  5. 数学への挑戦 第二弾〜期待値と分散:数理モデルxプログラミング〜
  6. 数学への挑戦 第二弾〜卒業までに彼氏ができる確率:数理モデルxプログラミング〜
  7. 数学への挑戦 第二弾〜確率変数の足し算:数理モデルxプログラミング〜
  8. 数学への挑戦 第二弾〜まとめ1:数理モデルxプログラミング〜

Java ポリモーフィズム(多様性) 〜実装をしてみる〜

イントロダクション

前回の学習を踏まえて、抽象クラス、インターフェースを使用して簡単なプログラムを作成してみようと考えています。

頭で理解しても、実践が伴わなければものになりません

前回の学習ポイント

継承関係を作り、下の図のようなクラス関係を作成しました。

そして、RpgCharacterクラスは、抽象クラスです。

以下のような手順で作成しました。

!. 通常のlクラスを作成する(RpgCharacter)

  1. 必要なプロパティ(属性を追加する)
  2. それぞれのGeter&Setterを作成
  3. このクラスを継承するすべてのクラスに共通するであろうメソッドを作成
    /** にげる */
    public void escape() {
    System.out.println(this.name + "は逃げ出した");
    }
  4. 実装する各クラスによって別の処理をさせたいので、抽象メソッドを作成
    /** 抽象メソッド「たたかう」 */
    public void attack(Monster monst);
  5. RpgCharacterクラスを継承して、Wizardクラスなどのクラスを作成する

このように、クラス関係を作ると、RpgCharacterクラスを継承したクラスを全てRpgCharacterクラス型の変数で各クラスオブジェクトを使用することができる。
<RpgCharacterクラス型の変数でいろんなクラスを使う>

public static void main(String[] args) {
        RpgCharacter[] party = new RpgCharacter[2];
        party[0] = new RpgHero("太郎");
        party[1] = new RpgWizard("二郎");

        System.out.println("こんにちは、良いパーティですね。");
        for (int i = 0; i < party.length; i++) {
            System.out.println(party[i].getName() + "さん");
        }
    }

ポリモーフィズムの実装

前回学習したものを実装して、「動くもの」を作成しようというところです。

実装する手順を考える

実装するのには、それなりの時間がかかりますが、やってみることの意義はすごく大きいです。

今回は、キャラクターを作成する処理から実装していこうと考えています。

<作成するものVersion1>

  1. 勇者とモンスターが1回ずつ攻撃する
  2. それぞれの攻撃に対して、各キャラクターのHPを減算する

メインメソッドの実装

ここでは、プログラムをイチから作成する方向で、話を進めていきます。

作成したプログラムは下のような実行結果が得られるように、実装します。

まずは、プログラムを実行するためのクラス(BattleSample.java)を作成します。エラーが出る部分はコメントアウトします。

つまるところは、どのような処理を呼び出したいかを実装します。ちなみにコメントのみでも良いです。

バージョン1の実装

<BattleSample.java-バージョン1

public static void main(String[] args) {
    //勇者クラスの生成 
    RpgHero hero = new RpgHero("勇者");
    // モンスタークラスの生成
    Slime slime = new Slime("スライムA");

    // 勇者の攻撃
    hero.attack(slime);
    // モンスターの攻撃
    slime.attack(hero);
}

このように、勇者クラスと、スライムクラスをインスタンス化してそれぞれのメソッド(コマンド)を呼び出してやるだけのシンプルな実装です。

これで、勇者とスライムの攻防がコンソール(標準出力)へ出力されます。

問題は、RpgHeroクラスとSlimeクラスができていないという部分です(前回の実装を行った人は作成済みです)

RpgHeroクラスを作る

このクラスは、下の図にあるように、RpgCharacterクラスを継承した形で、実装します。

なので、先にRpgCharacterクラスを作成する必要がありますので、こちらのクラスの製造に着手します。

RpgCharacterクラスの製造

このクラスは、湯者だけではなく魔法使いや、盗賊、戦士などのプレーヤー側のキャラクターに共通する部分を実装する
想定で、設計しました。

なので、下のように共通するもの(属性・振る舞い)を実装します。

つまり、現状では、通常のクラスになります。

public class RpgCharacter {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;
    /** 性別 */
    protected int sex;
    /** 年齢 */
    protected int age;
    /** 誕生日 */
    protected String birthDay;
   ・
   ・
   ・
}

上の状態では、属性(フィールド変数)を定義した状態です。

このほかに追加したいものもあるので、一度内容を確認します。

<RpgCharacterクラスの設計1>

  1. 属性、名前を持っている
  2. 属性、MPを持っている
  3. 属性、年齢を持っている
  4. 属性、性別を持っている
  5. 属性、誕生日を持っている

個の状態では、共通するプロパティ(属性)のみが定義されています。ほかにも考えれば出てきそうですが。。。

そして、共通するコマンド(メソッド)を定義します。

<RpgCharacterクラスの設計2>

  1. 属性、名前を持っている
  2. 属性、MPを持っている
  3. 属性、年齢を持っている
  4. 属性、性別を持っている
  5. 属性、誕生日を持っている
  6. 振る舞い、にげるを持っている

作成した設計を元に、そのクラスを実装します。

<RpgCharacter>バージョン1

public class RpgCharacter {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;
    /** 性別 */
    protected int sex;
    /** 年齢 */
    protected int age;
    /** 誕生日 */
    protected String birthDay;

    /** にげる */
    public void escape() {
        System.out.println(this.name + "は逃げ出した");
    }

フィールド変数には、本来「private」修飾氏をつけるのですが、今回は、子クラスを作成するための親クラスとして作成しているので、「protected」をつけて、継承関係のあるクラスであれば参照可能な形にしています。

そして、Getter, Setterは省略していますので、それぞれのメソッドが実装されているていで話を進めます。

この状態では、「たたかう」メソッドを強制的に継承する子クラスに実装させることができないので、下のような、抽象メソッドを追加します。

    /** たたかう */
    public abstract void attack(RpgCharacter character);

このようにすると、「抽象メソッドは抽象クラス、インターフェースでないともていない」ので、RpgCharacterクラスを通常のクラスから「抽象クラス」に変更します。

public abstract class RpgCharacter {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;
    /** 攻撃力 */
    protected int attackPower;
    /** 防御力 */
    protected int diffencePower;
    /** 性別 */
    protected int sex;
    /** 年齢 */
    protected int age;
    /** 誕生日 */
    protected String birthDay;

    /** 使用できるコマンドのメニューを開く */
    public abstract void showMenu();
    /** たたかう */
    public abstract void attack(RpgCharacter character);
    /** にげる */
    public void escape() {
        System.out.println(this.name + "は逃げ出した");
    }

そして、このクラスをインスタンス化するとき(newするとき)にデフォルトの値を設定するための

コンストラクタを定義(実装)します。引数に名前だけを与えた場合「コンストラクタ1」と、引数にすべてのプロパティ(属性)を与えた場合「コンストラクタ2」を定義しました。

    /** コンストラクタ1 */
    public RpgCharacter(String name) {
        this.name = name;
        this.hp = 10;
        this.mp = 0;
    }

    /** コンストラクタ2 */
    public RpgCharacter(String name, int sex, int age, String birthDay) {
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.birthDay = birthDay;
    }

RpgHeroを作る

ここでRpgHeroクラスの製造に戻ります。

ここまできたら、シンプルにRpgCharacterクラスを継承したRpgHeroクラスを作成するだけです。抽象メソッドのオーバーライドがありますが。。。

public class RpgHero extends RpgCharacter {
    /** コンストラクタ */
    public RpgHero(String name) {
        super(name);
    }
    /** コンストラクタ */
    public RpgHero(String name, int sex, int age, String birthDay) {
        super(name, sex, age, birthDay);
    }

    @Override
    public void attack(RpgCharacter monst) {
        System.out.println(this.name + "の攻撃");
        int damage = getAttackPower() - monst.getDiffencePower();
        System.out.println(monst.getName() + "へ" + damage + "のダメージ");
        monst.setHp(monst.getHp() - damage);
    }
}

継承したクラス(子クラス)から親クラスのコンストラクタ、メソッド、フィールドを呼び出したい場合は「super」をつけてやります。

同様に自分のクラス(子クラス)で保持するもの(コンストラクタ、メソッド、フィールド)を呼び出したい場合は「this」をつけてやります。

そして「@Override」というアノテーションがついているメソッドは、抽象メソッドを「オーバーライド」していることを明示的に示しています。

これと同様に、MonsterクラスとSlimeクラスも作成してしまいましょう。

Monsterクラスの製造

public class Monster extends RpgCharacter {

    /**
     * @param name
     */
    public Monster(String name) {
        super(name);
    }

    @Override
    public void attack(RpgCharacter player) {
        System.out.println(this.name + "の攻撃");
        int damage = getAttackPower() - player.getDiffencePower();
        System.out.println(player.getName() + "へ" + damage + "のダメージ");
        player.setHp(player.getHp() - damage);
    }
}

必要な属性(フィールド)はRpgCharacterクラスで持っているので、このクラスに特有な部分のみを実装します。

そして、コンストラクタに関しては、細かい情報(性別、年齢など)は必要な時にsetAge()などのメソッドで設定すれば良いので明示できに書きません。

その代わり、RpgCharacterクラスの、初期値としては「不明」「-1」などの値を設定するようにします。

int型は、参照型のようなnullという値が使えないので、-1で代用します。

つまりは、「年齢が『-1』だった場合『年齢不詳』という意味にする」というルールを追加してやれば、この問題は解決出るのでそのようにしたというところです。

スライムクラス

public class Slime extends Monster {

    /**
     * @param name
     */
    public Slime(String name) {
        super(name);
    }
}

このクラスに至っては、コンストラクタのみの実装で事足ります。

<<<前回

継承に関するページ一覧

  1. Java オブジェクト指向基礎 ~オブジェクト指向コンセプト~
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. Java クラスの継承を理解する
  4. クラスの継承〜アクセス修飾子〜
  5. クラスの継承関係を作る1
  6. クラスの継承関係を作る2

環境構築関連ページ一覧

設計関連ページ一覧

  1. 設計を始める〜1.アプリイメージ〜
  2. 設計を始める〜2.機能イメージ〜
  3. 設計を始める〜3.機能概要〜
  4. Java はじめて16 〜クラス設計から実装〜

PHP関連ページ

  1. WordPress プラグイン作成〜DBを使用する〜
  2. PHP PDO 〜MySQLにアクセスする〜
  3. PHP Ajax 〜DBに登録したデータを受信する〜
  4. Google Maps API PHP連携 〜マップ情報をDBに登録する〜
  5. PHP Image File 〜iPhoneやAndroidでの画像送受信の問題〜
  6. AngularJS Routing 〜PHPをWeb APIにする〜
  7. WordPress PHPカスタム〜根本的に見た目を変える〜
  8. WordPress PHPカスタム〜根本的に見た目を変える2〜
  9. Eclipse PHPプラグイン 〜ElipseでWordPress環境を構築〜
  10. WordPress テスト実装 〜heade-test.phpを表示〜
  11. AngularJS + PHP 〜WordPressと連携する〜
  12. AngularJS + PHP 〜AngularJSの実装〜
  13. AngularJS + PHP 〜AngularJSの実装2〜
  14. WordPress 処理解析 ~index.phpを眺める~
  15. WordPress Plugin NewStatPress ~アクセス解析プラグインAPIを使う~
  16. WordPress 処理解析 ~ログイン処理を調べる~
  17. WordPressカスタム〜アンケートボタンを追加する(設計)〜
  18. WordPressカスタム〜プラグインの作成〜
  19. WordPressカスタム〜ダッシュボードのプラグイン画面作成〜
  20. WordPressカスタム〜ダッシュボードのプラグイン画面作成2〜
  21. WordPressカスタム〜ダッシュボードのプラグイン画面作成3〜
  22. WordPress プラグイン作成〜アンケート作成プラグインを作る〜

JS関連ページ

  1. JS GoogleMaps API 〜オリジナル・データマップを作ろう〜
  2. 吹き出しにYoubetubeを埋め込む
  3. Ajax + XmlHttpRequest〜画像送信からDB登録して表示〜
  4. JS XmlHttpRequest 〜JSでの同期/非同期通信〜
  5. JS Google Maps API 〜GeoLocation 現在位置の取得〜
  6. AngularJS + PHP 〜AngularJSの実装〜
  7. AngularJS + PHP 〜AngularJSの実装2〜
  8. WordPress プラグイン作成 〜$wpdbでのSELECT〜
  9. WordPressプラグイン作成 〜HTML挿入まで完了〜
  10. WordPress プラグイン作成 〜アンケート挿入〜
  11. MAMP 起動設定 〜WordPressのテスト環境を作る〜
  12. MAMP WordPress 〜インポート時のエラー対処〜
  13. WordPress PHPカスタム〜根本的に見た目を変える2〜

数理モデル関連ページ

  1. 数学への挑戦 第二弾〜数理モデルxプログラミング〜
  2. 数学への挑戦 第二弾〜実装編:数理モデルxプログラミング〜
  3. 数学への挑戦 第二弾〜集合を使う:数理モデルxプログラミング〜
  4. 数学への挑戦 第二弾〜確率変数:数理モデルxプログラミング〜
  5. 数学への挑戦 第二弾〜期待値と分散:数理モデルxプログラミング〜
  6. 数学への挑戦 第二弾〜卒業までに彼氏ができる確率:数理モデルxプログラミング〜
  7. 数学への挑戦 第二弾〜確率変数の足し算:数理モデルxプログラミング〜
  8. 数学への挑戦 第二弾〜まとめ1:数理モデルxプログラミング〜

Java ポリモーフィズム(多様性) 〜クラス型の変換と組み合わせ〜

インロトダクション

前回は抽象クラスとインターフェースについて学習しました。

今回は、以下の3つを組み合わせて、どのような仕組みを作ることができるのか?について学習したいと思います。

はっきり言って、「どのような仕組みを作ることができるのか?」の問いに対する答えは、「ほぼ無限の組み合わせ方、仕組みを作ることができる」と思います。という答えが言えます。

前回までに、クラスとクラスを組み合わせるための土台になる部分を学習しました。以下のような内容です。

  • クラスの継承関係を作成する(親クラスと子クラス)
  • 抽象クラスとインターフェース

これらの仕組み(継承関係を作る)を使用して、どのような組み合わせ方ができるのか学習していきます。
世間巷には「デザインパターン」という名前で広く知られています。が、デザインパターンなどのように広く知られるものは
大体Java APIの方で実装してあるので、使い方さえ分かっていれば改めて実装する必要はありません。

ポイントになるのは、「クラス関係を作成して、どのような仕組みを実現するか?」というところです。

ポリモーフィズムの実装

「テキストRPGを作る」ということをテーマ(話題)として話を進めていきます。

前回までに作成したもの

親クラス、子クラス。。。として以下のようなクラスを作成したいと考えています。下のようなクラスたちです。

具体例A
テキストRPGゲームを作成しようとしているので下のようなクラスを作成したいと思っている。

  1. 勇者・クラス <作成済み>
  2. 魔法使い・クラス <作成済み>
    3.盗賊・クラス
  3. 超勇者クラス
  4. マタンゴ・クラス
  5. ポインズンマタンゴ・クラス
  6. ゴブリン・クラス
  7. ウェアウルフ・クラス
  8. デスバット・クラス

そして、プレーヤー側のクラスの親になるCharacterクラスも作成しました。(詳細は前回を参照ください。)

ポリモーフィズムの設計

先ずは、設計から入ります。

組み合わせて、プログラムを実行するのに「どう組み合わせるか?」を考えないと始まらないのです。

自分の場合は、まずは紙と鉛筆を持ってプログラミングを始めます。つまり「設計から始める」ということです。

RPGのパーティを考える

例えば、前回作成したCharacterクラスとは別に「RpgCharacter」というクラスを作成します。
このクラスは、下の図のように勇者クラス(RpgHero)や魔法使いクラスを作成したとします。

そうすると、下のようなコードが書けます。(エラーが出ません)

<メインメソッド>

    public static void main(String[] args) {
        RpgCharacter[] party = new RpgCharacter[2];
        party[0] = new RpgHero("太郎");
        party[1] = new RpgWizard("二郎");

        System.out.println("こんにちは、良いパーティですね。");
        for (int i = 0; i < party.length; i++) {
            System.out.println(party[i].getName() + "さん");
        }
    }

このように、RpgCharacterクラスを継承しているクラスなので、RpgCharacterの配列をパーティとして扱うことができます。

そして、MonsterもRpgCharacterを継承することになるので、モンスターも仲間(パーティ)に追加できます。

RpgCharacterに処理をまとめる

現状では、勇者や魔法使い、モンスターなどの使用できるコマンドは「たたかう」というコマンドのみです。

ここに、すべてのキャラクターに共通する「にげる」コマンドを追加します。
それには、下のようにコードを追加します。

<RpgCharacterクラスの修正>

public abstract class RpgCharacter {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;

    /** にげる */
    public void escape() {
        System.out.println(this.name + "は逃げ出した");
    }
}

この状態で、RpgCharacterクラスを継承するクラスは「にげる」コマンドを使用することができます。

しかし「全く同じではない処理を追加する場合」はどうでしょうか?

例えば、「たたかう」コマンドの場合です。勇者クラスと魔法使いクラスでは、攻撃力が違うはずです。

この場合は、与えるダメージの大きさをそのクラスによって変えられるようにする必要があります。

その仕組みとして「抽象メソッド」を使用する方法があります。

具体的には下のようなコードです。

<抽象メソッドを追加する>

    /** たたかう */
    public abstract void attack(RpgCharacter character);

実装したクラスのコードは下のようになります。

<抽象メソッドを追加したクラス>

public abstract class RpgCharacter {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;

/** たたかう */
    public abstract void attack(RpgCharacter character);
    /** にげる */
    public void escape() {
        System.out.println(this.name + "は逃げ出した");
    }

そして、これらのクラスを生成するとき(newするとき) には、コンストラクタが必要になりますが、これもRpgCharacterクラスと同じものになりますので、下のようにコンストラクタを追加します。

<コンストラクタを追加したクラス>

public abstract class RpgCharacter {
    /** 名前 */
    protected String name;
    /** HP */
    protected int hp;
    /** MP */
    protected int mp;

    /** コンストラクタ */
    public RpgCharacter(String name) {
        this.name = name;
        this.hp = 10;
        this.mp = 0;
    }

/** たたかう */
    public abstract void attack(RpgCharacter character);
    /** にげる */
    public void escape() {
        System.out.println(this.name + "は逃げ出した");
    }

そうすると初めにも書きましたが、このようなコードでの処理が実行できます。

    public static void main(String[] args) {
        RpgCharacter[] party = new RpgCharacter[2];
        party[0] = new RpgHero("太郎");
        party[1] = new RpgWizard("二郎");

        System.out.println("こんにちは、良いパーティですね。");
        for (int i = 0; i < party.length; i++) {
            System.out.println(party[i].getName() + "さん");
        }
    }

実行結果は下のようになります。

こんにちは、良いパーティですね。
太郎さん
二郎さん

<<<前回 次回 >>>

継承に関するページ一覧

  1. Java オブジェクト指向基礎 ~オブジェクト指向コンセプト~
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. Java クラスの継承を理解する
  4. クラスの継承〜アクセス修飾子〜
  5. クラスの継承関係を作る1
  6. クラスの継承関係を作る2

環境構築関連ページ一覧

設計関連ページ一覧

  1. 設計を始める〜1.アプリイメージ〜
  2. 設計を始める〜2.機能イメージ〜
  3. 設計を始める〜3.機能概要〜
  4. Java はじめて16 〜クラス設計から実装〜

PHP関連ページ

  1. WordPress プラグイン作成〜DBを使用する〜
  2. PHP PDO 〜MySQLにアクセスする〜
  3. PHP Ajax 〜DBに登録したデータを受信する〜
  4. Google Maps API PHP連携 〜マップ情報をDBに登録する〜
  5. PHP Image File 〜iPhoneやAndroidでの画像送受信の問題〜
  6. AngularJS Routing 〜PHPをWeb APIにする〜
  7. WordPress PHPカスタム〜根本的に見た目を変える〜
  8. WordPress PHPカスタム〜根本的に見た目を変える2〜
  9. Eclipse PHPプラグイン 〜ElipseでWordPress環境を構築〜
  10. WordPress テスト実装 〜heade-test.phpを表示〜
  11. AngularJS + PHP 〜WordPressと連携する〜
  12. AngularJS + PHP 〜AngularJSの実装〜
  13. AngularJS + PHP 〜AngularJSの実装2〜
  14. WordPress 処理解析 ~index.phpを眺める~
  15. WordPress Plugin NewStatPress ~アクセス解析プラグインAPIを使う~
  16. WordPress 処理解析 ~ログイン処理を調べる~
  17. WordPressカスタム〜アンケートボタンを追加する(設計)〜
  18. WordPressカスタム〜プラグインの作成〜
  19. WordPressカスタム〜ダッシュボードのプラグイン画面作成〜
  20. WordPressカスタム〜ダッシュボードのプラグイン画面作成2〜
  21. WordPressカスタム〜ダッシュボードのプラグイン画面作成3〜
  22. WordPress プラグイン作成〜アンケート作成プラグインを作る〜

JS関連ページ

  1. JS GoogleMaps API 〜オリジナル・データマップを作ろう〜
  2. 吹き出しにYoubetubeを埋め込む
  3. Ajax + XmlHttpRequest〜画像送信からDB登録して表示〜
  4. JS XmlHttpRequest 〜JSでの同期/非同期通信〜
  5. JS Google Maps API 〜GeoLocation 現在位置の取得〜
  6. AngularJS + PHP 〜AngularJSの実装〜
  7. AngularJS + PHP 〜AngularJSの実装2〜
  8. WordPress プラグイン作成 〜$wpdbでのSELECT〜
  9. WordPressプラグイン作成 〜HTML挿入まで完了〜
  10. WordPress プラグイン作成 〜アンケート挿入〜
  11. MAMP 起動設定 〜WordPressのテスト環境を作る〜
  12. MAMP WordPress 〜インポート時のエラー対処〜
  13. WordPress PHPカスタム〜根本的に見た目を変える2〜

数理モデル関連ページ

  1. 数学への挑戦 第二弾〜数理モデルxプログラミング〜
  2. 数学への挑戦 第二弾〜実装編:数理モデルxプログラミング〜
  3. 数学への挑戦 第二弾〜集合を使う:数理モデルxプログラミング〜
  4. 数学への挑戦 第二弾〜確率変数:数理モデルxプログラミング〜
  5. 数学への挑戦 第二弾〜期待値と分散:数理モデルxプログラミング〜
  6. 数学への挑戦 第二弾〜卒業までに彼氏ができる確率:数理モデルxプログラミング〜
  7. 数学への挑戦 第二弾〜確率変数の足し算:数理モデルxプログラミング〜
  8. 数学への挑戦 第二弾〜まとめ1:数理モデルxプログラミング〜

Java 未来に備えるための継承 〜親クラスの作成とインターフェース〜

イントロダクション

前回は、継承に関して学習しました。

継承関係を作る目的は大まかにしたの2つがあります。

  1. クラスのグループ化
  2. クラスの拡張

そして、クラスをグルーピング、拡張することで以下のようなメリットがあります。

  • 親クラスのメソッドも使用できる
  • 親クラスと似て非なるメソッドができる

この特性を使用して、実際に使用されているのがJava APIにあります。

<画面コンポーネント系のクラス(java.net)>

<インターフェースのケース>

  • java.util.List
    ArrayList, LinkedListなどのクラスをグルーピングしている
  • java.util.Set
    HashSet, EnumSet名どのクラスをグルーピング
  • java.util.Map
    HashMap, LinkedMapなどのクラスをグルーピング

未来に備える実装の例

具体例A
テキストRPGゲームを作成しようとしているので下のようなクラスを作成したいと思っている。

  1. 勇者・クラス
  2. 魔法使い・クラス
    3.盗賊・クラス
  3. 超勇者クラス
  4. マタンゴ・クラス
  5. ポインズンマタンゴ・クラス
  6. ゴブリン・クラス
  7. ウェアウルフ・クラス
  8. デスバット・クラス

これらのクラスを作るのに、全てのクラスに「HP」「名前」が必要になりますが、毎回同じコードを書くのは
スマートではありませんので「継承(extends)」を行うことでこれらを解消することができました。
※↑前回の学習内容

そして、インターフェースも同様に「同じカテゴリ」のクラスを作ることができます。

具体的には、自分が作成した「CommandIF」のことです。

<=========今回の学習ポイント=====================>

  1. 今回は、通常のクラスにある、メソッドとは別の「抽象メソッド」に関して学びます。
  2. 通常のクラス + 「抽象メソッド」= 【抽象クラス】
  3. 「抽象メソッド」と定数のみ = 【インターフェース】

<=======================================>

未来に備えるための継承

プログラミングを行う時には、大まかに2種類あります。

  1. 目的のものを実装する
  2. 今後あると便利なものを実装する

※普段から今後使えるものを作ろうとするのは基本ですが。。。

先ほどの具体例Aを例にすると、下のようなクラス群を作成するのに共通するプロパティ(属性)を持ったクラスを継承して作成するのが、良さそうです。※この時点では、アイディアのレベルで良いのです。

  1. 勇者・クラス
  2. 魔法使い・クラス
    3.盗賊・クラス
  3. 超勇者クラス
  4. マタンゴ・クラス
  5. ポインズンマタンゴ・クラス
  6. ゴブリン・クラス
  7. ウェアウルフ・クラス
  8. デスバット・クラス

なので、これらのクラスに共通するプロパティ(属性)を考えます。
UMLを使用すると、直感的に考えることができます。

とりあえずは。このような形で、クラスの継承関係を作成すると「HP」と「名前」はCharacterクラスのみに作成すれば問題なくできそうです。

2つの不都合

ここで不都合が生じます。具体的には「詳細不明のメソッド」が出てくるというところです。

具体的問題は、

「勇者クラスと魔法使いクラスの攻撃力、ダメージは同じでしょうか?」

答えはNOだと思います。そんな魔法使いがいても良いのかもしれませんが。。。

しかし、勇者と魔法使いが同じ攻撃を行うのでは、職種が違う意味がありません。

なので、「戦う」というメソッドの処理内容をそれぞれのクラスで別の処理にしてやる必要があります。

ただし、メソッドの名前は同じである必要があります。

なので、HeroやWizardなどのプレーヤー側のクラスの親になるクラス「Character」を作成してやれば、コードとしては下のような形になります。共通するプロパティ(属性)は全てCharacterクラスで管理するようにします。

<Heroクラス>

package yoshida.tkm.lesson10;

/**
 *
 * @author 作成者の名前
 * 2021/05/19
 */
public class Hero extends Character {
    /** 定数 */
    final String TEISU = "定数";

    /** コンストラクタ */
    public Hero() {
        // newしたときに呼び出される
        System.out.println("*** Hero コンストラクタ ***");
    }

    /** 戦う */
    public void attack(Matango m) {
        System.out.println(getName() + "の攻撃");
        m.hp -= 5;
        System.out.println("5ポイントのダメージをあたえた!");
    }

    /** 逃げる */
    public void run() {
        // コメント
        System.out.println(getName() + "は逃げ出した!");
    }
}

CharacterクラスにHPと名前が定義してあるので、これらのフィールド変数は親クラスのものを使用します。

そして、Heroクラスには「戦う」と「逃げる」、のコマンドがあります。

<Wizardクラス>

public class Wizard extends Character {
    public void heal(Hero hero) {
        hero.setHp(hero.getHp() + 10);
        System.out.println(hero.getName() + "のHPを10ポイント回復した");
    }
 }

Wizardクラスは回復の魔法が使えます。そして、HP、名前は親クラスのものを使用します。

ここで問題なのは。。。

勇者クラスでなくとも「戦う」コマンドは使用できなくてはおかしい、というところです。
なので、上記のWizardクラスにattack()メソッドを追加します。

<Wizardクラス②>

public class Wizard extends Character {
    /** 戦う */
    public void attack(Matango m) {
        System.out.println(getName() + "の攻撃");
        m.hp -= 5;
        System.out.println("5ポイントのダメージをあたえた!");
    }

public void heal(Hero hero) {
        hero.setHp(hero.getHp() + 10);
        System.out.println(hero.getName() + "のHPを10ポイント回復した");
    }
 }

この状態では、勇者クラスの「戦う」と同じ処理になりますが、魔法使いは別な「戦う」方法があるはずです。

この部分の解決方法としては抽象メソッドを使用するという方法があります。

具体的には、Characterクラスに抽象メソッドをもたせてやるという方法です。

しかし、「抽象メソッドをもたせると、通常のクラスではなく抽象クラスとして定義する」必要があります。

通常のクラスと違い下のように定義します。

「書き方」
public abstract class クラス名{
// 通常クラスと変わらないが抽象メソッドを作る必要がある
public abstract 返却値 メソッド名(引数);
}

<Characterクラス>

public abstract class Character {
    // java.lang.Character;
    private String name;
    private int hp;
    private int mp;

    /** 抽象メソッド */
    public abstract void attack(Matango m);

/**
     * @return the name
     */
    public String getName() {
        return name;
    }
    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * @return the hp
     */
    public int getHp() {
        return hp;
    }
    /**
     * @param hp the hp to set
     */
    public void setHp(int hp) {
        this.hp = hp;
    }
    /**
     * @return the mp
     */
    public int getMp() {
        return mp;
    }
    /**
     * @param mp the mp to set
     */
    public void setMp(int mp) {
        this.mp = mp;
    }
}

これで、HeoクラスとWizardクラスは同じ名前で全く別の処理**のメソッドを作成することができます。
さらに、メソッドの
オーバーライド**を強制させることができるので、オーバーライドのし忘れを防止することができます。

public class Wizard extends Character {
    /** 戦う */
    @Override
    public void attack(Matango m) {
        System.out.println(getName() + "の攻撃");
        m.hp -= 2;
        System.out.println("2ポイントのダメージをあたえた!");
    }

<<<前回 次回>>>

継承に関するページ一覧

  1. Java オブジェクト指向基礎 ~オブジェクト指向コンセプト~
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. Java クラスの継承を理解する
  4. クラスの継承〜アクセス修飾子〜
  5. クラスの継承関係を作る1
  6. クラスの継承関係を作る2

環境構築関連ページ一覧

設計関連ページ一覧

  1. 設計を始める〜1.アプリイメージ〜
  2. 設計を始める〜2.機能イメージ〜
  3. 設計を始める〜3.機能概要〜
  4. Java はじめて16 〜クラス設計から実装〜

PHP関連ページ

  1. WordPress プラグイン作成〜DBを使用する〜
  2. PHP PDO 〜MySQLにアクセスする〜
  3. PHP Ajax 〜DBに登録したデータを受信する〜
  4. Google Maps API PHP連携 〜マップ情報をDBに登録する〜
  5. PHP Image File 〜iPhoneやAndroidでの画像送受信の問題〜
  6. AngularJS Routing 〜PHPをWeb APIにする〜
  7. WordPress PHPカスタム〜根本的に見た目を変える〜
  8. WordPress PHPカスタム〜根本的に見た目を変える2〜
  9. Eclipse PHPプラグイン 〜ElipseでWordPress環境を構築〜
  10. WordPress テスト実装 〜heade-test.phpを表示〜
  11. AngularJS + PHP 〜WordPressと連携する〜
  12. AngularJS + PHP 〜AngularJSの実装〜
  13. AngularJS + PHP 〜AngularJSの実装2〜
  14. WordPress 処理解析 ~index.phpを眺める~
  15. WordPress Plugin NewStatPress ~アクセス解析プラグインAPIを使う~
  16. WordPress 処理解析 ~ログイン処理を調べる~
  17. WordPressカスタム〜アンケートボタンを追加する(設計)〜
  18. WordPressカスタム〜プラグインの作成〜
  19. WordPressカスタム〜ダッシュボードのプラグイン画面作成〜
  20. WordPressカスタム〜ダッシュボードのプラグイン画面作成2〜
  21. WordPressカスタム〜ダッシュボードのプラグイン画面作成3〜
  22. WordPress プラグイン作成〜アンケート作成プラグインを作る〜

JS関連ページ

  1. JS GoogleMaps API 〜オリジナル・データマップを作ろう〜
  2. 吹き出しにYoubetubeを埋め込む
  3. Ajax + XmlHttpRequest〜画像送信からDB登録して表示〜
  4. JS XmlHttpRequest 〜JSでの同期/非同期通信〜
  5. JS Google Maps API 〜GeoLocation 現在位置の取得〜
  6. AngularJS + PHP 〜AngularJSの実装〜
  7. AngularJS + PHP 〜AngularJSの実装2〜
  8. WordPress プラグイン作成 〜$wpdbでのSELECT〜
  9. WordPressプラグイン作成 〜HTML挿入まで完了〜
  10. WordPress プラグイン作成 〜アンケート挿入〜
  11. MAMP 起動設定 〜WordPressのテスト環境を作る〜
  12. MAMP WordPress 〜インポート時のエラー対処〜
  13. WordPress PHPカスタム〜根本的に見た目を変える2〜

数理モデル関連ページ

  1. 数学への挑戦 第二弾〜数理モデルxプログラミング〜
  2. 数学への挑戦 第二弾〜実装編:数理モデルxプログラミング〜
  3. 数学への挑戦 第二弾〜集合を使う:数理モデルxプログラミング〜
  4. 数学への挑戦 第二弾〜確率変数:数理モデルxプログラミング〜
  5. 数学への挑戦 第二弾〜期待値と分散:数理モデルxプログラミング〜
  6. 数学への挑戦 第二弾〜卒業までに彼氏ができる確率:数理モデルxプログラミング〜
  7. 数学への挑戦 第二弾〜確率変数の足し算:数理モデルxプログラミング〜
  8. 数学への挑戦 第二弾〜まとめ1:数理モデルxプログラミング〜

Java クラスの継承を理解する

イントロダクション

Javaなどのオブジェクト指向言語では、ほとんどの言語がクラスの継承を行うことができます。なので、継承するとどのようなメリットがあるのか、それとも意味のないことなのか?ここを判断してクラス設計を行えるようになるための考え方を伝えられれば良いと思っています。

継承を行うメリットに関して、お話する前に予備知識として次の部分を理解しておいて干飯です。

前提1:データ型、演算子などを理解している

データ型などの説明をしている記事の一覧、検索結果です

前提2:Javaの基本文法の理解をしている

これも基本文法の記事を検索した結果のリンクです。

継承のついて

今回は、クラスの継承関係を作成しその関係について記載しました。
継承関係を作って実行してみました。 => 親、兄、弟のクラスを作成して実行した動画です。

クラスの継承

クラスの継承を行う目的は大まかに2つあります。

  1. 作成するクラスをグループ化したい
  2. 親クラスを拡張したい

上記のような目的が多いです。

==クラスの継承方法==
<親クラスの例>

package jp.zenryoku.practice.train2.cls.familly;

public class Parent extends Gosenzo {
/** 家計 */
public static int kakei = 1000;
/** 苗字 */
protected String lastName;
/** 名前 */
private String name;
/** 年齢 */
private int age;
/** 趣味・特技 */
public String favorit;

/** コンストラクタ */
public Parent() {
lastName = "tanaka";
name = "takao";
age = 50;
favorit = "ケツで箸を割る";
}

/** Gosenzoクラスの抽象メソッド */
@Override
public String kekkeiGenkai() {
return "白目をむく";
}

/** 自己紹介 */
public void say() {
System.out.println(lastName + "と申します。");
System.out.println("親です。名前は" + name + "です。年齢は" + age + "です。");
System.out.println("特技は、「" + favorit + "」です。");
}

/** おかしな部分 */
protected void funny() {
System.out.println("喜びを真逆の言葉で表現する。");
}

/** 買い物 */
public void buy(int money) {
kakei -= money;
System.out.println("残金:" + kakei);
}
}

<子クラスの例>

package jp.zenryoku.practice.train2.cls.familly;

import java.util.List;

import jp.zenryoku.practice.train2.cls.game.util.CommandData;
import jp.zenryoku.practice.train2.cls.game.util.CommandIF;

public class ChildAni extends Parent implements CommandIF {
/** 年齢 */
private int age;
/** 名前 */
private String name;

public ChildAni() {
name = "taro";
age = 12;
createCommandList();
}

@Override
public void say() {
System.out.println(lastName + "です。");
System.out.println("兄です。名前は" + name + "です。年齢は" + age + "です。");
System.out.println("特技は、「" + favorit + "」です。");
}

@Override
public List<CommandData> getCommandList() {
addCommand(createCommandData("すかしっぺ", 15));
addCommand(createCommandData("漢の一撃", 20));
return super.getCommandList();
}

/**
* コマンド実行する
* @param index
*/
public int exeCommand(String index) {
CommandData data = super.getCommandList().get(Integer.parseInt(index));
System.out.println(this.name + "の" + data.getCommandName());
return data.getCommandValue();
}
}

このようなクラスを題材に話を進めていきたいと思います。

クラスをグループ化する

クラスをグループ化する場合、上記の「親クラス」と「子クラス」の場合は、人間の親子を表しています。

なので、Parentクラスのグループ(親クラス)に対して子クラスは、兄とか弟ができるというところです。

しかし、このグループに車とか、犬などの子クラス(Parentクラスを継承したクラス)を作ると「役割」がまとまらなくなってしまいます。

なので、同じカテゴリのもの(クラス)**を作成していきましょう。

実際に、このグループに属するクラス「弟」クラスを作成すると下のようになります。

package jp.zenryoku.practice.train2.cls.familly;

public class ChildOtoto extends Parent {
/** 年齢 */
private int age;
/** 名前 */
private String name;

public ChildOtoto() {
name = "jiro";
age = 10;
favorit = "鼻を膨らます";
}

@Override
public void say() {
System.out.println(lastName + "といいます。");
System.out.println("弟です。名前は" + name + "です。年齢は" + age + "です。");
System.out.println("特技は、「" + favorit + "」です。");
}

@Override
public void funny() {
super.funny();
}
}

このクラス以外にも、姉、妹、孫など作成することが可能です。※犬なども作れますが、混乱の元なのでやめましょう。

クラスを拡張する

そして、「クラスを継承する目的」その2に関してです。

Parentクラスは以下の属性(フィールド変数)を持っています。

    /** 家計 */
public static int kakei = 1000;
/** 苗字 */
protected String lastName;
/** 名前 */
private String name;
/** 年齢 */
private int age;
/** 趣味・特技 */
public String favorit;

なので、このParentクラスは「家系」を管理しているクラスというとこができます。

そして、このクラスを継承したクラスChildAniは親クラスの「buy()」メソッドを使用することができます。

つまり、親クラスにあるkakeiを参照することができます。アクセス修飾子が「public」だからというのもありますが。。。

結局のところは、親クラスのメソッドを使用することができるというところです。

ちょっと待て〜い

「拡張」する話はどこに行ったのか?と疑問に思う方もいると思います。

まずは、上記の「親クラスのメソッドも使用できる」というところが大切なのです。

この親クラスのメソッドを使用できるというところで、子クラスでは同じメソッドを定義した場合どのようになるのでしょうか?

オーバーライド

このようになります。「オーバーライドって何?」と思った方、通常でございます。

この「オーバーライド」こそが「拡張」する部分になります。

元々あったメソッド「親クラスのbuy()」メソッドは子クラスからでも下のような書き方で呼び出すことが可能です。

super.buy();

逆に下のように書いた場合

this.buy();

これは、子クラスに書いたbuy()メソッドを呼び出すことになります。

具体的には下のようなコードになります。
<親クラスを拡張した兄クラス>

public class ChildAni extends Parent implements CommandIF {
  ・
  ・※省略
  ・
/** 買い物 */
public void buy(int money) {
// 親クラスの処理から値引き処理( - nebiki)が追加されている
int nebiki = 100;
kakei -= (money - nebiki);
System.out.println("残金:" + kakei);
}
}

親クラスでの「buy(買い物)」メソッドでは引数の値を「kakei(家計)」から直接、減算していましたが、兄クラスでは「値引き」が入ります。

このように、親クラスのbuy()メソッドを使うよりも、兄クラスのbuy()メソッドを使用した方が安く済むということです。

これを現実に例えていうならば、親よりも、兄の方が買い物上手といったところでしょうか?

次回

継承に関するページ一覧

  1. Java オブジェクト指向基礎 ~オブジェクト指向コンセプト~
  2. UMLの書き方(読み方)〜概要とクラス図〜
  3. Java クラスの継承を理解する
  4. クラスの継承〜アクセス修飾子〜
  5. クラスの継承関係を作る1
  6. クラスの継承関係を作る2

環境構築関連ページ一覧

設計関連ページ一覧

  1. 設計を始める〜1.アプリイメージ〜
  2. 設計を始める〜2.機能イメージ〜
  3. 設計を始める〜3.機能概要〜
  4. Java はじめて16 〜クラス設計から実装〜

PHP関連ページ

  1. WordPress プラグイン作成〜DBを使用する〜
  2. PHP PDO 〜MySQLにアクセスする〜
  3. PHP Ajax 〜DBに登録したデータを受信する〜
  4. Google Maps API PHP連携 〜マップ情報をDBに登録する〜
  5. PHP Image File 〜iPhoneやAndroidでの画像送受信の問題〜
  6. AngularJS Routing 〜PHPをWeb APIにする〜
  7. WordPress PHPカスタム〜根本的に見た目を変える〜
  8. WordPress PHPカスタム〜根本的に見た目を変える2〜
  9. Eclipse PHPプラグイン 〜ElipseでWordPress環境を構築〜
  10. WordPress テスト実装 〜heade-test.phpを表示〜
  11. AngularJS + PHP 〜WordPressと連携する〜
  12. AngularJS + PHP 〜AngularJSの実装〜
  13. AngularJS + PHP 〜AngularJSの実装2〜
  14. WordPress 処理解析 ~index.phpを眺める~
  15. WordPress Plugin NewStatPress ~アクセス解析プラグインAPIを使う~
  16. WordPress 処理解析 ~ログイン処理を調べる~
  17. WordPressカスタム〜アンケートボタンを追加する(設計)〜
  18. WordPressカスタム〜プラグインの作成〜
  19. WordPressカスタム〜ダッシュボードのプラグイン画面作成〜
  20. WordPressカスタム〜ダッシュボードのプラグイン画面作成2〜
  21. WordPressカスタム〜ダッシュボードのプラグイン画面作成3〜
  22. WordPress プラグイン作成〜アンケート作成プラグインを作る〜

JS関連ページ

  1. JS GoogleMaps API 〜オリジナル・データマップを作ろう〜
  2. 吹き出しにYoubetubeを埋め込む
  3. Ajax + XmlHttpRequest〜画像送信からDB登録して表示〜
  4. JS XmlHttpRequest 〜JSでの同期/非同期通信〜
  5. JS Google Maps API 〜GeoLocation 現在位置の取得〜
  6. AngularJS + PHP 〜AngularJSの実装〜
  7. AngularJS + PHP 〜AngularJSの実装2〜
  8. WordPress プラグイン作成 〜$wpdbでのSELECT〜
  9. WordPressプラグイン作成 〜HTML挿入まで完了〜
  10. WordPress プラグイン作成 〜アンケート挿入〜
  11. MAMP 起動設定 〜WordPressのテスト環境を作る〜
  12. MAMP WordPress 〜インポート時のエラー対処〜
  13. WordPress PHPカスタム〜根本的に見た目を変える2〜

数理モデル関連ページ

  1. 数学への挑戦 第二弾〜数理モデルxプログラミング〜
  2. 数学への挑戦 第二弾〜実装編:数理モデルxプログラミング〜
  3. 数学への挑戦 第二弾〜集合を使う:数理モデルxプログラミング〜
  4. 数学への挑戦 第二弾〜確率変数:数理モデルxプログラミング〜
  5. 数学への挑戦 第二弾〜期待値と分散:数理モデルxプログラミング〜
  6. 数学への挑戦 第二弾〜卒業までに彼氏ができる確率:数理モデルxプログラミング〜
  7. 数学への挑戦 第二弾〜確率変数の足し算:数理モデルxプログラミング〜
  8. 数学への挑戦 第二弾〜まとめ1:数理モデルxプログラミング〜

Java Basic 実践学習編 〜変数の使用とデータ型、条件分岐、コードブロック〜

イントロダクション

前回は「Java Basic 実践学習編 〜ハローワールドから変数の宣言・初期化〜」を行いました。

今回は、表題の通りです。

変数の使用

前回も行いましたが、下のように、変数を宣言、初期化して使用します。

変数の宣言と初期化

<Code.09>

public class HelloWorld {
    public static void main(String[] args) {
        // 変数の宣言
        int seisu;
        // 変数の初期化
        double shosu = 0.0;
        // 変数の初期化
        String moji = "文字列";
    }
}
九九の二の段

<Code.10>

public static void main(String[] args) {
    int a = 2;
    int x = 1;
    System.out.println("2 x 1 = " + a * x);
    x++;
    System.out.println("2 x 2 = " + a * x);
    x++;
    System.out.println("2 x 3 = " + a * x);
    x++;
    System.out.println("2 x 4 = " + a * x);
    x++;
    System.out.println("2 x 5 = " + a * x);
    x++;
    System.out.println("2 x 6 = " + a * x);
    x++;
    System.out.println("2 x 7 = " + a * x);
    x++;
    System.out.println("2 x 8 = " + a * x);
    x++;
    System.out.println("2 x 9 = " + a * x);
}

上のコードは、九九の二の段を表示するプログラムです。ここでは変数xの値をインクリメントすることで、二の段の計算結果を表示しています。

変数の宣言と初期化を確認したところで次のコードに行きます。

コードブロック

一旦立ち止まって振り返ります。今まで動かしていた「メインメソッド」は下のように書きます。
この時に「{」から「}」までの間がメインメソッドの範囲、コードブロックになります。

<Code.11>

public static void main(String[] args) {
    // 何かしらの処理
}

これは決まっている部分ですので、そのまま覚えても問題ありません。と言うか自分は覚えました。

ポイント

「{}」は「中かっこ」、「波かっこ」など色々な言い方がありますが、「{}」の括弧で囲まれた部分が「ブロック」になります。
具体的には<Code.11>の「{」から「}」までの間が「(コード)ブロック」にあたります。

これは、スコープともいい「{」から「}」までの間だけ変数が機能します。
具体的には、下のように書くと変数「num」はエラーになると言うところです。

変数の有効範囲

<Code.12>

public static void main(String[] args) { // ここからメインメソッドのブロック
    int a = 0;
    if (a == 1) { // ここからIFのブロック
        int num = 0;
        num++;
    } else { // ここからelseのブロック
        num = 10; // ここでエラー
    }
}

「{」から「}」までの間が、変数のスコープ、機能する範囲なのでif() { ... }の中で宣言(初期化)された変数「num」はelse { ... }の範囲では機能しないのです。

詳細は以下のようになります。

  1. 1行目はメインメソッドの定義、メソッドの宣言
  2. 2行目でint型(整数型)の変数「a」の初期化
  3. if文で「aの値が1のときIFブロックに処理が進む」
  4. 同様に「if文の条件以外のばあいelseのブロックに進む」

この様に、メインメソッドのブロックの中に、ifのぶろっくとelseのブロックがあります。

そして、これを次のように書き換えるとエラーは出ません。

<Code.13>

public static void main(String[] args) {
    int a = 0;
    int num = 0;
    if (a == 1) {
        num++;
    } else {
        num = 10;
    }
}

変数「num」がメインメソッドのスコープ内で宣言されているので、その中にあるif() { ... }の中でもelse { ... }でも両方で機能することができます。

なので、次のようなコードでは、メソッドの中で宣言していてもエラーになります。別のメソッドだから、スコープの範囲が違うためです。

<Code.14>

public static void main(String[] args) {
    int a = 0;
    int num = 0;
    if (a == 1) {
        num++;
    } else {
        num = 10;
    }
}

/** メンバメソッド */
public void test1() {
    num; // ここでエラー
    System.out.println("test1");
    System.out.println("2 / 2 = " + 2 / 2);
}

ポイント

変数のスコープと言うのがありそれは「{」から「}」までの間がその範囲になります。
なので変数の宣言が、「{」から「}」までの間の外にあればそれはそれはエラーになります。

クラスとメソッドについて

今までプログラムを何個か作成してきましたが、Javaのプログラムを動かすための単位は「クラス」になります。
このクラスは下のように書き、フィールドとメソッドを持っています。

<Code.15>

public class HelloWorld {
    /** フィールド */
    private int field;

    /** メソッド */
    public void method(String hikisu) {
        int a = 0;
        int num = 0;
        if (a == 1) {
            num++;
        } else {
            num = 10;
        }
    }
}

このルールで、作成したクラスに「メインメソッド」を追加しているのです。今までに作成したものはメインメソッドのみでしたが。。。クラスとしては成り立つのです。ちょっと極端ですが、空クラスも、作成すればあります。

public class Kara {
}

Javaの実装ルールに違反していないのでOKなのです。まぁ作成する意味もないですが。。。

条件分岐

if文

次は、<Code.13>で出てきたif文に関して学習します。
俗にいう条件分岐です。これは、プログラムを実行するときに「~の場合の処理」と条件を付けて処理を分けたいときに使用します。具体的に以下のようなコードです。

<Code.16>

public static void main(String[] args) {
    int num = 10;
    if (num == 10) {
        System.out.println("No10");
    } else {
        System.out.println("Not No10");
    }
}

int型(整数型)の変数numが10の時「No10」とコンソールに表示します。それ以外の時は「Not No10」と表示します。
この場合は、プログラムを書き換えて変数numの値を変更してやる必要があります。

なので、プログラム引数を使用してプログラムを書き換えなくてもよいように修正します。

プログラム引数

プログラム引数は、Javaプログラムを実行するときに渡せる引数のことで、引数はString型の値になります。
ただし、文字列を複数渡すことができるのでString[](String型の配列)になっています。

具体的には下のように使用します。

コードとしては、動画のものと違いますが、下のように使います。

public static void main(String[] args) {
    // プログラム引数を取得する
    int num = Integer.parseInt(args[0]);
    if (num == 10) {
        System.out.println("No10");
    } else {
        System.out.println("Not No10");
    }
}

しかし、このコードでは、プログラム引数が渡されてないい場合はエラーになります。

なので次のように書き換えます。
<Code.17>

public static void main(String[] args) {
    // プログラム引数を取得する
    int num;
    if (args[0] != null && args[0].matches("[0-9]{1}")) {
        num = Integer.parseInt(args[0]);
    } else {
        num = 10;
    }

    if (num == 10) {
        System.out.println("No10");
    } else {
        System.out.println("Not No10");
    }
}

このように、想定外の入力があったときを考慮してプログラムを作成するとエラーが出ない、安全なプログラムができます。リアルでもプログラムでも安全第一です

処理の内容に関して
初めの

if (args[0] != null && args[0].matches("[0-9]{1}")) {

を分解して説明します。
if文に関しては後に説明しますが、

args[0].matches("[0-9]{1}") {

の部分に関して
この部分はString型のメソッドを使用しています。実はString型はJavaAPIで定義されているクラスなのです。
String[]はString型の配列ですので、配列の中身はString型の変数です、

String[0]

String[] hako = {"もじ", "123", "aaa"};

と初期化したときの「"もじ"」に当たります。
つまり

String[0] => "もじ", String[1] => "123", String[2] => "aaa"

となります。

なので、Stringクラスのメソッド「matches」を使用することができます。

このメソッドの処理は引数に「正規表現」を渡し返り値に正規表現にマッチするかどうか?を返す処理になります。

具体的には下のようになります。
<Code.18>

public static void main(String[] args) {
    String aa = "12345";
    boolean isNumber = aa.matches("[0-9]{1,}");
    System.out.println("入力値: " + aa + "は、正規表現「[0-9]{1,}」にマッチするか?: " + isNumber);

    boolean isAtoZ = aa.matches("[A-Z]{1,}");
    System.out.println("入力値: " + aa + "は、正規表現「[0-9]{1,}」にマッチするか?: " + isAtoZ);
}

実行結果は以下の通りです。

条件分岐本題

if文になれてきたところで、プログラムを理解していきましょう。

<Code.13>を見てください。初めのif文で変数aaの値が10の時...と処理が書いてあります。

public static void main(String[] args) {
    int num = 10;
    if (num == 10) {
        System.out.println("No10");
    } else {
        System.out.println("Not No10");
    }
}

ここでのnum == 10の部分が論理式になります。論理式とは返却値に真偽値(trueもしくはfalse)を返します。
コードで書くと下のようになります。

boolean is10 = num == 10;

何度も記載しますが、booleanは真偽値のデータ型です。true, falseどちらかの値しか持ちません。
なので、変数「num」が10の場合は、true, そうでない場合はflaseが変数「is10」に代入されます。

ちょっと座学臭い感じですが、「=」演算子は式の値を代入します。
初めの方に実装しましたが、変数の初期化を行った時には「=」で宣言と同時に値を代入します。

int num = 10;

同様に、初期化でなくても値は代入する事ができます。

num = 9;

下のように、プログラムを書いたときは変数「num」の値が変わって聞きます。そして、プログラムは必ず上から下に流れます。
<Code.19>

public static void main(String[] args) {
    int num = 10;
    if (num == 10) {
        num = 20;
    } else {
        num = 3;
    }
    if (num == 20) {
        System.out.println("Hello");
    } else {
        System.out.println("Bye");
    }
}

このコードは、「Hello」が表示されます。以下のように処理が進みます。

  1. int型の変数numを10で初期化
  2. もしnumが10であれば、numに20を代入
    3.それ以外ならnumに3を代入
  3. もしnumが20であれば、「Hello」を表示
  4. それ以外なら「Bye」を標示

条件分岐のバリエーション

if-elseを理解できたと思います。これに追加してelse-ifがあります。具体的には下のように書きます。
<Code.20>

public static void main(String[] args) {
    int num = 10;
    if (num == 10) {
        num = 20;
    } else if (num == 20){
        num = 3;
    } else {
        num = 2;
    }
    if (num == 20) {
        System.out.println("Hello");
    } else if (num == 3) {
        System.out.println("Else if");
    } else {
        System.out.println("Bye");
    }
}

今までの条件に「そのほかに、もしnumが20の時」という文言が加わりました。
作り方はif文の時と同じです。

文章をつなげると「もじnumが10ならば~その他にもし、numが20ならば~、それ以外なら~」というような文章、プログラムができました。

switch文

switch文はif文と同じです。ただ書き方が違います。
if文は以下のように書きます。

if (論理式A) {
    // 論理式Aがtrueときの処理
} else if (論理式B) {
    // 論理式Bがtrueときの処理
} else {
    // 何かしらの処理
}

switch文は以下の通りです。

switch (変数) {
case XX:
    // 変数がXの時のケース
    break;
case YY:
    // 変数がYの時のケース
    break;
default:
    // 変数が上記以外のとき
}

<Code.20>をswitch文に書き換えると下のようになります。

public static void main(String[] args) {
    int num = 10;
    switch (num) {
    case 10:
        System.out.println("No8");
        break;
    case 20:
        System.out.println("No9");
        break;
    default:
        System.out.println("それ以外");
    }
}
ポイント

このプログラムの

break;

に注目して下さい。この分がないとどうなるでしょうか?
<Code.21>

switch (num) {
case 8:
    System.out.println("No8");
case 9:
    System.out.println("No9");
default:
    System.out.println("それ以外");
}
if (num == 0) {
    break;
}

出力結果はいかのようになりました。入力値は「8」です。

8
No8
No9
それ以外

入力値が「9」の場合は

9
No9
それ以外

同様に上記以外の入力、「5」を入力しました。

5
それ以外

つまるところは、breakがないとそれ以降の処理がすべて動いてしまうということです。

ループ文

while文

やって来ました。ループ文です。ここまで来た方おめでとうおございます。
プログラミングで遊ぶ材料がそろいました。

まずは下のループ文を見てください。

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);

    while(true) {
        int num = scan.nextInt();

        switch (num) {
        case 8:
            System.out.println("No8");
            break;
        case 9:
            System.out.println("No9");
            break;
        default:
            System.out.println("それ以外");
        }
    }
}
while(true) { ... }

これは無限ループのプログラムの型です。
「{}」の間(スコープ)を無限ループします。

このままだとプログラムが終了しません。

では、どのようにプログラムを終了するか?

特定の入力があった場合にプログラムを終了するようにプログラムを作ります。

今回利用しているJavaAPIは、java.util.Scannerです。
そして、使用しているメソッドはnextInt()です。

終了するための処理は下のコードです。

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);

    while(true) {
        int num = scan.nextInt();

        switch (num) {
        case 8:
            System.out.println("No8");
            break;
        case 9:
            System.out.println("No9");
            break;
        default:
            System.out.println("それ以外");
        }
        if (num == 0) {
            break;
        }
    }
}

上のコードを説明すると。。。

  1. Scanner scan = new Scanner(System.in);で標準入力の受付クラスをインスタンス化
    標準入力を受け付けられるようにします。
  2. while(true) {で無限ループを開始します。
  3. int num = scan.nextInt();で標準入力を待ち受けます。
  4. あとはswitch文で受け取った値の判定をしてそれぞれの処理を行います。
  5. if (num == 0) {入力値を代入した変数「num」が0の場合「{}」内の処理を行います。
  6. break;無限ループを抜けます。

for文

この無限ループは、ゲームを作成するときの基本的なプログラムになります。
そして、今回は回数制限のある「おみくじゲーム」を作成します。

占い回数を入力して、今日の運勢を%で算出します。

public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);

    System.out.println("今日の運勢を占います。占う回数を入力してください。");
    int num = 0;
    while(true) {
        num = scan.nextInt();
        if (num > 3) {
            System.out.println("3以下の値を入力してください");
            continue;
        }
        break;
    }
    System.out.println(num + "回占います。");

    int sisu = 0;
    for (int i = 0; i < num; i++) {
        int unsei = new Random().nextInt(3);
        if (unsei == 0) {
            System.out.println((i + 1) + "回目: 大吉");
            sisu += 4;
        } else if (unsei == 1) {
            System.out.println((i + 1) + "回目: 中吉");
            sisu += 3;
        } else if (unsei == 2) {
            System.out.println((i + 1) + "回目: 吉");
            sisu += 2;
        } else {
            System.out.println((i + 1) + "回目: 凶");
            sisu += 1;
        }
    }
    System.out.println("sisu: " + sisu);
    int un = new BigDecimal(sisu).divide(new BigDecimal(num * 4), 2, RoundingMode.DOWN).multiply(new BigDecimal(100)).intValue();
    System.out.println("un: " + un);
    System.out.println("今日の運勢は、" + un + "%好調です。");
}

これを改造するもよし、アイディアを出して別のものにするもよし、
遊んでみてください。

ポイント

今回使用したループ文はfor文といって下のように書きます。

for (カウンタの初期化; ループする論理式; ループした後の処理) {
    // 何かしらの処理
}

これは、どのような意味かというとfor int i = 0; i < 10; i++) { .. }<code>とコードを書いたときの場合は、int(整数)型の変数を0で初期化(</code>int i = 0<code>)して、この変数が10よりも小さい(i < 10)間、ループするたびにあとの処理(</code>i++)を行います。

ループ文の練習です、下のような問題があります。

問題1「4回ループするfor文を作ってください」

<for文の場合>

for (int i = 0; i < 5; i++) {
    System.out.pprintln("Hello" + i);
}

処理の順序は下のようになります。

  1. int型(整数型)の変数iを0で初期化
  2. i = 0なので論理式「i < 5」の評価後の値は「0 < 5」でtrue
  3. 論理式の値がtrueなので「{}」の中の処理を行う
  4. 「Hello0」を表示した後に
    i++

    の処理を行う

  5. iが1になったので、論理式
    i < 5

    の評価の値は「1 < 5」でtrue

  6. 「Hello1」を表示した後に
    i++

    の処理を行う

  7. iが2になったので、論理式
    i < 5

    の評価の値は「2 < 5」でtrue

  8. 「Hello2」を表示した後に
    i++

    の処理を行う

  9. iが3になったので、論理式
    i < 5

    の評価の値は「3 < 5」でtrue

  10. 「Hello3」を表示した後に
    i++

    の処理を行う

  11. iが4になったので、論理式
    i < 5

    の評価の値は「4 < 5」でtrue

  12. 「Hello4」を表示した後に
    i++

    の処理を行う

  13. iが5になったので、論理式
    i < 5

    の評価の値は「5 < 5」でfalse

  14. 論理式の値がfalseになったのでループを終了する

<while文の場合>

int i = 0;
while(i < 5) {
    System.out.println("Hello" + i);
    i++;
}
  1. int型(整数型)の変数iを0で初期化
  2. i = 0なので論理式「i < 5」の評価後の値は「0 < 5」でtrue
  3. 論理式の値がtrueなので「{}」の中の処理を行う
  4. 「Hello0」を表示した後に
    i++

    の処理を行う

  5. iが1になったので、論理式
    i < 5

    の評価の値は「1 < 5」でtrue

  6. 「Hello1」を表示した後に
    i++

    の処理を行う

  7. iが2になったので、論理式
    i < 5

    の評価の値は「2 < 5」でtrue

  8. 「Hello2」を表示した後に
    i++

    の処理を行う

  9. iが3になったので、論理式
    i < 5

    の評価の値は「3 < 5」でtrue

  10. 「Hello3」を表示した後に
    i++

    の処理を行う

  11. iが4になったので、論理式
    i < 5

    の評価の値は「4 < 5」でtrue

  12. 「Hello4」を表示した後に
    i++

    の処理を行う

  13. iが5になったので、論理式
    i < 5

    の評価の値は「5 < 5」でfalse

  14. 論理式の値がfalseになったのでループを終了する

こんな風に作成します。

今までに学習してきたことは大まかに下のようなことです。

  • リテラルの理解
  • 変数・データ型の理解
  • 条件分岐の理解
  • ループ文、繰り返し処理の理解

これらの処理、文法がプログラミングの基本になります。この基本は「初めの一歩」にして「奥義」たりえます。
基本を極めればどんなプログラムでも対応する事ができます。

そして、楽しく学習するのが一番学習効果が高いので「楽しく」プログラミングできるように想像力を働かせましょう。

具体的には「~出来たら面白そうだ」などと考えてみましょう。もしかしたらものすごい発見があるかもしれません。

でわでわ。。。

<<<前回

Java Basic 実践学習編1 〜ハローワールドから変数の宣言・初期化〜

Javaの実践学習

今までに、色々と学習してきましたが、効率と理解度を考慮に入れるとズバリ下のような学習方法が一番だと思いました。

  1. コードを書く
  2. コードを動かす
  3. コードを書き換えて動かしてみる
  4. コードを理解する

この順序でいろんな書き方、プログラムの組み方を理解していくのが最もわかり易く、実践で使えると思いました。

この手順を使用してJavaの基本をやり直したいと思います。

初めてのJava

以前書いた記事はこちらです。

Lv1.ハローワールド

初めてのプログラムとして有名なものですが、これはJava言語に限ったことではありません。C言語、Python, C#, java script etc ...でも同じことです。
プログラムを起動して、「Hello World」と表示するだけのプログラムです。

このプログラムは、大きなアプリケーションに新たに取り組む、もしくはフレームワークを使用するなどの時に「プログラムが動くよね?」という確認のために使用することが多いです。

そして、自分はJava屋なので、Java言語で実装を行います。

下のコードは、「Hello クラス」を作成し、そこにメインメソッドを作成しました。とりあえずこれを書き写して動かしてみましょう

<Code.01>

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

Eclipse(開発ツール(IDE))での実行した時の動画は以下になります。

シンプルに、コンソール(標準出力)への文字列出力になります。

ポイント1

プログラムが動くことを確認するというところです。

Lv2.適当な文字の出力

上のコードを書き換えて、出力内容を変更します。

<Code.02>

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("I am Takunoji. It's verry hard.");
    }
}

出力した文言の言っていることは、意味がわかりませんが、とりあえずは、出力内容が変わります。

コードの実行確認は、読者の皆さんが行ってください。
※コピペしないほうが、理解も早いです。

ポイント2

"(ダブルクォーテーション)で囲った部分が文字列としてJVM(Javaを起動する機械、java.exeのこと)に、認識されます。
まとめると下のようなイメージになります。

System.out.println(「文字列」);

この「文字列」の部分を引数と呼びます。<Code.02>のコードを説明すると
printlnメソッドの引数に文字列「I am Takunoji. It's verry hard.」を渡している」と説明できます。

よくあるミス

下のコードはエラーになります。

<Code.03>

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("I am Takunoji. It's verry hard.);
    }
}

すぐに気がつく人は気がつくのですが、気がつかない人はなかなか気がつきません。
自分がそうです。苦労しました、今でも、汚いコードとかにある、このような「小さなミス」を見つけるのに一苦労します。

コードは綺麗に書きましょう

一言で言うと自分があとで苦労します。。。

余談:綺麗なコードとは

単純に、以下の部分がポイントです。

  1. インデントが揃っている
  2. 余計な変数宣言がない
  3. 同じ名前の変数を別の用途に使いまわさない
  4. 処理が整理されていて、どの処理がどこにあるのかわかるようになっている

大まかに上のようなコードです。詳細に関しては、今後理解して行けば良いと思います。とりあえず書いて動かしてみましょう。

Lv3.計算をしてみる

単純な足し算と引き算をコンソールに出力します。

<Code.04>

public class HelloWorld {
    public static void main(String[] args) {
        // 足し算
        System.out.println("1 + 1 = " + (1 + 1));
        // ひき算
        System.out.println("1 - 1 = " + (1 - 1));
    }
}

上のコードは、文字列「1 + 1 = 」に「1 + 1」の計算結果を文字列として連結して、出力しています。
次の行では、同様に、文字列「1 - 1 = 」に「1 - 1」の計算結果を文字列として連結して、出力しています。

ポイント3

ポイント2でも説明しましたが、System.out.println("1 + 1 = " + (1 + 1));<code>の</code>"1 + 1 = " + (1 + 1)の部分が引数になります。
この引数は"1 + 1 = "<code>が文字列を示し、</code>(1 + 1)が計算処理でその結果は2になります。
最後に、"1 + 1 = " + (1 + 1)にある真ん中の「+」が文字列の連結処理を行っているところです。

文字列の隣に来る「+」は文字連結を示します。

では、次のコードを見て見ましょう、掛け算と割り算です。

<Code.05>

public class HelloWorld {
    public static void main(String[] args) {
        // かけ算
        System.out.println("2 * 2 = " + 2 * 2);
        // わり算
        System.out.println("2 / 2 = " + 2 / 2);
    }
}

ポイント4

このコードは、掛け算と割り算を行なっています。しかし、<Code.04>と比べてみるとかっこが足りません。
具体的に"1 + 1 = " + (1 + 1)<code>と</code>"2 * 2 = " + 2 * 2の部分です。

この部分は暗黙的なルールがあり、中学生くらいに習ったと思いますが、「足し算と掛け算」があったら「掛け算」の方を先に計算すると言うルールがあったと思います。

プログラムでも同じなんです。

つまるところは以下のような理由で、上のような違いがあります。

<足し算と引き算の場合>

public static void main(String[] args) {
    // 足し算
    System.out.println("1 + 1 = " + (1 + 1));
    // ひき算
    System.out.println("1 - 1 = " + (1 - 1));
}

足し算と引き算の場合は、()かっこが必要です。それは「文字を連結する」と言う処理と、「計算をする」と言う処理にしようする演算子(「+」のこと)が同じなため

"1 + 1 = " + 1 + 1

のように書くと文字連結か、計算するかJavaコンパイラが判別できないためエラーになります。

<掛け算と割り算の場合>

public static void main(String[] args) {
    // かけ算
    System.out.println("2 * 2 = " + 2 * 2);
    // わり算
    System.out.println("2 / 2 = " + 2 / 2);
}

見た目にも、「+」と「*」で演算子が違うので「文字列の連結」と「計算」の区別がつきます。なのでかっこがなくてもビルドエラーになりません。

ついでにもう1つサンプルコード
<Code.06>

public class HelloWorld {
    public static void main(String[] args) {
        // かけ算と割り算
        System.out.println("2 * 2 = " + 2 * 2 / 2);
    }
}

この場合はどうのような処理結果が出るでしょうか?それは実行して見てからのお楽しみ。

変数を使う

プログラミングを行なっていると「変数」と言う言葉が出てきます。
プログラミングは、中学校くらいに習った(習う)数学と似たところがあります。

演算子 意味 サンプルコード
+ 足し算、文字列の連結 1 + 1, "文字" + "1"
- 引き算 1 - 1
* かけ算 1 * 1
/ わり算 1 / 1
% 剰余算 1 % 1
剰余算について

<Code.07>

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello World");
        System.out.println("3 % 2 = " + 3 % 2);
    }
}

上のように割った後の余りを算出します。「3 / 2 = 1 あまり1」と言うふうになります。なので「3 % 2」の計算結果は「1」になります。

実際に使用するときは「変数Xが偶数か奇数か?」と調べるときに、下のような形で使用します。

<Code.08>

public class HelloWorld {
    public static void main(String[] args) {
        int X = 32;
        boolean isKisu =  X % 2 == 1;
    }
}

このときに変数Xを2で割った時の余りが1になる数は「奇数」です。逆に「0」になるものは偶数です。

このような「法則のようなもの?」を見つけてそれをプログラムに落とし込むと言うところもプログラミングの面白いところです。

変数を学ぶ

プリミティブ型の変数としては以下のようなものがあります。

[プリミティブ型]と呼ばれるデータ型の種類

データ型          読み      用途
byte            バイト        8ビットの整数(-127から127) を示すが実際はファイル入出力時にこのデータ型で扱うことが多い
int               イント        整数として使用する(四則計算など)、整数の計算で使用する事が多い
long              ロング      intよりも大きい数値を使用する時に使用する、日付計算などで使用する事が多い。
double          ダブル        小数点をつける数値として使用する
float            フロート    あまり使わない
char           キャラ          一文字を示す、またintでも扱うことができる 'a'(シングルクォーテーション使用)
boolean        ブーリアン 真(true)か偽(false)を示す、intではtrue=1, false=0

これは全てではないですが、大まかに変数の一覧になっています。

そして、よく使用するのが、以下の4つです。

  1. int型: 整数用の変数
  2. double型: 少数用の変数
  3. boolean型: 真偽値
  4. String型:文字列として使用する

今までにも使用しているコードですが、改めて眺めて見ましょう

<Code.09>

public class HelloWorld {
    public static void main(String[] args) {
        // 変数の宣言
        int seisu;
        // 変数の初期化
        double shosu = 0.0;
        // 変数の初期化
        String moji = "文字列";
    }
}

変数の宣言は値を代入しません。

int seisu;

、そして、初期化は値を代入します

int double shosu = 0.0;

上記ひと通りの内容を説明した動画が、以下になります。

四則計算の実装

次は、四則計算をプログラムで行います。上記の計算でも行いましたが、今回は変数を使用して実行します。

九九(2の段)を算出、表示する

サンプルコードは以下になります。

ポイント5

<Code.10>

public static void main(String[] args) {
    int a = 2;
    int x = 1;
    System.out.println("2 x 1 = " + a * x);
    x++;
    System.out.println("2 x 2 = " + a * x);
    x++;
    System.out.println("2 x 3 = " + a * x);
    x++;
    System.out.println("2 x 4 = " + a * x);
    x++;
    System.out.println("2 x 5 = " + a * x);
    x++;
    System.out.println("2 x 6 = " + a * x);
    x++;
    System.out.println("2 x 7 = " + a * x);
    x++;
    System.out.println("2 x 8 = " + a * x);
    x++;
    System.out.println("2 x 9 = " + a * x);
}

表示結果は以下になります。

ポイント

変数「a」と「x」を初期化して、掛け算した結果を表示しています。そして表示処理

System.out.println("XXXX");

)の間にある

x++;

の処理は「インクリメント」と言って変数の値に「プラス1」します。
なので、これは2の段を表示できているのです。

今回は、ここまでです。次は、変数を使用して、簡単なプログラムを作成します。