Java Basic Class Inheritance ~クラスの継承関係を作る1:親と兄と弟の作成~

継承したクラスを動かす

クラスの継承関係を作成して、それを実行してクラス継承の意味と使い方を理解していきます。
その第一回目となります。
前回の記事ではアクセス修飾子の継承関係を作ったときにどのような違いがあるのか記載しています。

親クラスと子クラスを実行イメージ

JFrameクラスを継承して画面作成

Java Swingで、幅300, 高さ300の画面に座標(100,100)から幅100、高さ100の円を0度から300度までの線を引きました。JFrameを継承、paint()をオーバーライドします

前提

以下のクラスを作成します。親、子(兄)、子(弟)、メインクラス

  1. Parent(親)
  2. ChildAni(兄)
  3. ChildOtoto(弟)
  4. MainFamilly(メインクラス)

それぞれ以下のようなコードです。
そして、MainFamilyクラスはメインメソッドを持っているクラスです。このクラスを用意することでほかのクラスを修正してもメインメソッドを修正せずに起動できるというわけです。

具体的には以下のような手順で起動確認しながら実装ができるというわけです。

  1. MainFamilly以外のクラスを修正する
  2. MainFamillyクラスのメインメソッドを起動する

Parent

下に定義している子クラスが継承するクラスです。このクラスは、フィールド変数に「public static」のものと「protected」のものがあります。このフィールド変数は、子クラスから参照することができます。が「private」になっている変数は参照できません。

public class Parent {
    /** 家計 */
    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 = "ケツで箸を割る";
    }

    /** 自己紹介 */
    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);
    }
}

ChildAni

子クラス1です。Parentクラスを継承しています。Parentクラスの「Say()」メソッドをオーバーライドしています。

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

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

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

ChildOtoto

子クラス2です。Parentクラスを継承しています。Parentクラスの「Say()」メソッドをオーバーライドしています。

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();
    }
}

MainFamilly

public class MainFamilly {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.println("**** Game Start ****");
        Parent parent = new Parent();
        ChildAni ani = new ChildAni();
        ChildOtoto ototo = new ChildOtoto();
        while (true) {
            String input = scan.nextLine();
            if ("parent".equals(input)) {
                parent.say();
            } else if ("ani".equals(input)) {
                ani.say();
            } else if ("ototo".equals(input)) {
                ototo.say();
            } else {
                System.out.println("処理を終了します。");
                break;
            }
        }
    }
}

実践してみましょう

まずは、MainFamillyクラスを起動してみましょう。
実行結果はどのようなものでしょうか?

ParentクラスChildAniクラスの違いは以下の部分です。

Parentのコンストラクタ

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

Parent#say()

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

ChildAniのコンストラクタ

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

ChildAni#say()

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

ポイント

使用しているフィールド変数は全く同じものでしょうか?確認してみてください。アクセス修飾子をみて判断しましょう。
アクセス修飾子は下のような意味があります。

アクセス修飾子

public: どこからでも参照できる
protected: パッケージ内、クラスの継承関係がある場合に参照できる
private: クラスの中でのみ参照できる

まとめ1

アクセス修飾子によって、継承関係を作成したクラスの間で、参照する変数が変わります。
この特性を使用して、変数名が同じでも参照する変数が変えることができます。
「だからなに?」と聞かれそうですが、ここでの言いたいことはクラス固有の変数を持つことができるというところです。

ご先祖を作る

上記の記述では、Parent, ChildAni, ChildOtotoの3クラスを作成しました。ここまでで、クラスの継承に関しては理解できたと思います。注意点としてはアクセス修飾子です。この違いが理解できればオッケーです。

そして次の話に行きます。「ご先祖を作成する」というふうにきさいしましたが、抽象クラスを作成する方向で話を進めます。

抽象クラスとは

こちらの記事に記載されていたのは下のような文言です。

抽象クラスの代表的なクラスがあります。それは「Calendarクラス」です。このクラスは、抽象クラスなので「new」できません。
なので、「Calendar.getInstance();」のようにインスタンス取得メソッドを使用します。
このメソッドを使用してインスタンスを取得する方法は、「new」するときに固定の方法をプログラマーに強制させることができます。
つまり、ほかの方法で「new」できないということです。

抽象クラスとは、抽象メソッドを 1 つ以上持つクラスです。そのクラスだけでは意味を持たず、サブクラスに継承されることで初めて機能します。

抽象メソッドとは、以下のように記述されるメソッドです。abstract の後に、戻り値の型、メソッド名、引数の型、引数の数のみを定義し、処理内容は実装されません。具体的な処理内容は、抽象クラスを継承するサブクラスで実装されます。

早い話が、下のように通常のクラスに「抽象メソッドを持っている」というところです。

アクセス修飾子 abtract 戻り値の型 メソッド名(引数); 

サンプルコード(ご先祖)

public abstract class Gosenzo {
    /** 秘伝 */
    public String hiden;

    public Gosenzo() {
        hiden = "秘伝のタレ";
    }

    /** 血継限界 */
    protected abstract String kekkeiGenkai();
}

このご先祖クラスを親クラスに継承します。
そうすると、ビルドエラーが出ます。

このビルドエラーは、「抽象メソッドのオーバーライド」を行ていないために出たエラーです。

つまり、抽象メソッドを実装することを強制できるというわけです。逆に言うとGosenzoクラスを継承したクラスは、必ずkekkeiGenkai()メソッドがあるということです。

当然、抽象クラスにはメソッドの中身(処理)を書いていないので、Gosenzoクラスを継承したクラスは、必ずkekkeiGenkai()を持っていることになります。

具体的に、ご先祖を継承したParentクラスの血継限界が「"Hello Japan!"」を標準出力へ出力するものでParent2クラスの血継限界が「"Good Night"」を標準出力へ出力するものだったとします。

そうしたときに、下のようなコードを使用するとGosenzoクラスの中小メソッドを使用することで、kekkeiGenkai()の処理内容を別のものにすることができます。

public static void main(String[] args) {
    Gosenzo g1 = new Parent();
    Gosenzo g2 = new Parent2();
    g1.kekkeiGenkai();
    g2.kekkeiGenkai();
}

これが、抽象クラスの扱い方の一つです。

しかし、、実際にはこのようなクラス関係を作成することはありません。わかりやすいように作っているだけです。具体的には「デザインパターン」を使用したり、自分で考えたクラス関係を特定の目的のために作ります。

次回予告

次回は、作成した上記のクラスを修正していろいろと動かしてみます。

でわでわ。。。

<<< 前回 次回 >>>

関連ページ一覧

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX関連ページ

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  4. Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

オブジェクト指向関連ページ

  1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
  2. オブジェクト指向の概念2〜クラスとは〜

クラス間の継承を作る〜準備編:アクセス修飾子を理解する〜

イントロダクション

「基本文法がわかったから、簡単なプログラムなら組めるようになった。」は、「戦いの舞台に立った」状態です。
ここからが、戦いの始まりです。上の「基本文法がわかった」は処理を行う「メソッドが作れるようになった」ということです。これができないと始まらな。。。

今度は、この「メソッド」を自在に呼び出してメンテナンスのしやすいシステムを組みましょうというのが目標になります。

まとめると次のような形です。

  • 基本文法の理解:メソッドを作れるようになった。
  • クラスの扱い方の理解:メンテナンスのしやすいシステムを組める

ある意味「永遠のテーマ」ですが「メンテナンスのしやすいシステム」を組めるように良い設計=良いプログラムを組めるようになる。
これが、目標になります。

クラスの継承

クラス継承の方法は、簡単です。下のようにコードを書けば良いです。

public class Child1 extends Parent { ... } 

継承関係を作ると、子クラスが親クラスの実装を受け継ぎ拡張することができます。

クラスの継承関係を作るときはクラス毎に役割を分担し、実装の依存関係を分断できるように作ります。詳細は下のリンクを参照下さい

Java クラスの扱い〜役割分担をする〜

クラスの書き方などは下のリンクを参照下さい。
Java Basic Class 〜クラスを作ってクラスを理解する〜
Java Basic Class 〜クラスを使うサンプル〜

プログラムコードにすると下のような形です。

/** 親クラス */
public class Parent {
    private int age;
    private String name;

    /** コンストラクタ */
    public Parent(String name) {
        this.age = 24;
        this.name = name;
    }
    public void greet() {
        System.out.println("Hello World");
    }
    public void call() {
        System.out.println("Help!");
    }
}

/** 子クラス */
public class Child extends Parent {
    /** コンストラクタ */
    public Child() {
        super("Takunoji");
    }
    @Override
    public void greet() {
        System.out.println("Hello Brother");
    }
}

親クラス(Parent)を継承して子クラス(Child)を作成しています。
【ポイント1】
「new」したときに起動するコンストラクタは子クラスで「suepr()」を使用して親クラスのコンストラクタを呼び出しています。

【ポイント2】
子クラスのメソッド「greet()」は親クラスのメソッドをオーバーライドしています。

<オーバーライドのサンプル>
この動画では、JFrameクラスを継承してクラスを作成しています。親クラスのメソッド「paint()」メソッドをオーバーライドしています。

つまり、オーバーライドすると子クラスのメソッドが呼び出されるということです。
※親クラスのオブジェクト(インスタンス)で呼び出した場合は親クラスのメソッドが呼ばれます。

public static void main(String[] args) {
    Parent parent = new Parent("Taro");
    parent.greet();// Parentクラスのメソッド
    parent.call();// Parentクラスのメソッド

    Child child = new Child();
    child.parent(); // Childクラスのメソッド(オーバーライドしている)
    parent.call();// Parentクラスのメソッド
}

継承したときのテクニック

継承関係を作ることのメリットとしては、同じコードを書かなくてよいところです。
上の例では、変数のアクセス修飾子を「private」にしているので子クラスから参照することができませんが
これを「protected」に変更してやれば、子クラスでもフィールド変数「age, name」を参照することができます。

また、メソッドでオーバーライドしているもの(greet())とそうでないものがあります(call())がそれぞれ子クラスのインスタンスから呼び出すことができますが、オーバーライドしているメソッドは親クラスのメソッドを呼び出すことができません。それは、オーバーライドしているからです。
もし、呼び出したいのであれば、子クラスの中で「super.call()」と書く必要があります。

ここからが本題です。

アクセス修飾子

継承関係を作成したあとには、フィールド変数や、メソッドを定義します。

これらは「メンバ」と呼ばれインスタンスを生成して使用する事が多いです。インスタンスを生成しない場合はstatic修飾子をつけて使用します。

前置きはさておきにして具体的な使い方などに触れていきます。

変数のスコープprivate

まずは、下の様にクラスの継承関係を作ります。

親クラス

public class Parent {
    protected static int kakei = 1000;
    protected Stirng lastName;
    private String name;
    private int age;
       /** コンストラクタ */
       public Parent() {
          lastName = "test";
          name = "taro";
          age = 50;
       }
    public void say() {
       System.out.println("My name is " + name + " " + lastName + " and " + age + "years old.");
    }
}

子クラス

public class Child1 {
    private String name;
    private String age;
    public Child1 {
       name = "polo";
       age = 15;
    }
    @Overeide
    public void say() {
      System.out.println("My name is " + name + " " + lastName + " and " + age + "years old.");
    }
}

メインメソッド

public static void main(String[] args) {
    Parent p = new Parent();
    p.say();
    Child1 c1 = new Child1();
    c1.say));
}

そして、上の様な処理を実装したら
どんな出力が得られるでしょうか?
注意点としては、アクセス修飾子により、アクセスするフィールド変数が異なるところです。実行して確かめてみてください。

変数のスコープprotected

次は、protectedについて見てみます。
ParentクラスのlastNameに着目してください。2つのクラスの出力は、「test」になったと思います。これは継承関係があるクラス間で共有出来る、スコープが継承関係のあるクラス間で使用出来る様になっているからです。※パッケージ内でも使える様です。
これらのクラスのコードをいじっていろんな出力を確認してみてください。
きっと、クラスの継承とはどんなものか?の答えが見えて来ると思います。
実際に作る時は、UML など使うとわかりやすいと思います。
例えば、RPGゲームを作ろうとした場合には、以下のような登場人物がいます。

  • ゲームプレイする「プレーヤー・キャラクター」
  • モンスターなどのコンピュータが操作する「ノンプレイヤー・キャラクター」

それぞれの登場人物を「クラス」で表現してみると継承関係を作るメリットがより明確に分かると思います。
Java テキストRPG(戦闘シーンのみ)を再作成する~LWJGLを参考に作り直す~
Java テキストRPG(戦闘シーンのみ)を再作成する2~設計からやり直す~


でわでわ。。。

次回 >>>

関連ページ一覧

Java Basic1 〜文字列操作(Stringクラス)の扱い

文字列の操作

1.1 文字列処理とは

ズバリ、文字列を切り貼りします

例:1.1 「文字列を切り取る」
「こんにちは世界」という文字列の"ちは"を切り取ると「こんに世界」になります。
コードで書くと下のようなコードになります。Javaのプログラムで実行する時には下のようなコードで実行します。あくまでもサンプルなのでやり方は自分で考えて作れるようにしたいですね。

処理の内容などは、これから学んでいきます。

/**
 * 文字列の操作。
 *
 */
public class StringControl {

    /**
     * 動かしたいメソッドを呼び出してやれば動かせます。
     * 例として「1.1文字列処理とは」のサンプルコードを呼び出しています。
     *
     * @param args
     */
    public static void main(String[] args) {
        StringControl main = new StringControl();
        main.substringTest();
    }

    /**
     * 「1.1.1文字列処理とは」のサンプルコード。
     * 文字列を切り取る処理のサンプル<br/>
     * <br/>
     * <b>「こんにちは世界」という文字列の"ちは"を切り取る</b>
     */
    public void substringTest() {
        // 変数の初期化
        String moji = "こんにちは世界";
        // *******************************************************//
        // * やり方1:Stringクラスのメソッド「substring()」を呼び出す *
        // *******************************************************//
        String rightStr = moji.substring(0, 3);
        String leftStr  = moji.substring(5, 7);
        System.out.println("切り取った結果1は「" + rightStr + leftStr + "」です。");

        // *******************************************************//
        // * やり方2:char型の配列を取り出してやる                   *
        // *******************************************************//
        char[] charMoji = moji.toCharArray();
        // 切り取った結果を格納する
        char[] resArray = new char[charMoji.length];
        int resCount = 0;
        for (int i = 0; i < charMoji.length; i++) {
            if (i != 3 && i != 4) {
                // 表示する文字を設定(セット)する
                resArray[resCount] = charMoji[i];
                resCount++;
            }
        }
        // char型の配列をStringとして生成
        String resString = new String(resArray);
        System.out.println("切り取った結果2は「" + resString + "」です。");
    }

    /**
     * 「1.2.1とは」のサンプルコード。
     * 文字列を調査するサンプル<br/>
     * <table>
     *     <thead>
     *         <tr><th>操作</th></tr></tr>
     *         <th>メソッド定義(シグニチャ)</th></tr>
     *     </thead>
     *     <tbody>
     *         <tr><td>内容が等しいか調べる</td></tr>
     *         <tr><td>public boolean equals(Object o)</td></tr>
     *     </tbody>
     * </table>
     */
    public void checkString() {

        String moji = "test";

        // String#equals()
        if (moji.equals("test")) {
            System.out.println("mojiは\"test\"です。");
        } else {
            System.out.println("mojiは\"test\"ではありません。");
        }

        // String#equalsIgnoreCase()
        if (moji.equalsIgnoreCase("Test")) {
            System.out.println("mojiは\"Test\" or \"Test\"です。");           
        } else {
            System.out.println("mojiは\"Test\" or \"Test\"ではありません。");          
        }

        // String#isEmpty()
        if (moji.isEmpty()) {
            System.out.println("mojiは\"\"です。");
        } else {
            System.out.println("mojiは\"\"ではありません。");
        }
    }
}

1.2 基本的な文字列操作

操作 メソッド定義(シグニチャ)
内容が等しいか調べる public boolean equals(Object o)
大文字小文字を区別せず内容が等しいか調べる public boolean equalsIgnoreCase(String s)
文字列長を調べる public int length()
空文字か調べる public boolean isEmpty()

Sample1 1-1 文字列調査メソッドを利用した例

※クラス全体ではなく、メソッド部分のみを記述します。

使用するメソッド一覧
String#equals()
String#equalsIgnoreCase()
String#isEmpty()

/**
 * 文字列調査(文字列が等しいか?)のサンプル。
 * 「リスト1-1 文字列調査メソッドを利用した例」
 */
public void sample1_1StringEquals() {
    // 文字列を比較した場合
    System.out.println("*** String#equals() Sample1 ****");
    if ("test".equals("tezt")) {
        System.out.println("\"test\"と\"tezt\"は等しいです。");
    } else if ("test".equals("tezt") == false) {
        System.out.println("\"test\"と\"tezt\"は等しくありません。");
    } else {
        // 実際は例外しか返ってこないので意味のないコード
        // 想定外のケースも考慮に入れる
        System.out.println("trueもfalseも帰ってこなかった場合。");
    }
    System.out.println("*** String#equals() Sample2 ****");
    // 変数に入れた文字列を比較した場合
    String str = "test";
    String str2 = "tezt";
    if (str.equals(str2)) {
        System.out.println("\"test\"と\"tezt\"は等しいです。");
    } else {
        System.out.println("\"test\"と\"tezt\"は等しくありません。");
    }
    System.out.println("*** String#equalsIgnoreCase() Sample1 ****");
    if ("test".equalsIgnoreCase("tezt")) {
        System.out.println("\"test\"と\"tezt\"は等しいです。");
    } else if ("test".equalsIgnoreCase("tezt") == false) {
        System.out.println("\"test\"と\"tezt\"は等しくありません。");
    } else if ("test".equalsIgnoreCase("Test")) {
        System.out.println("\"test\"と\"Test\"は等しいです。");
    } else {
        // 実際は例外しか返ってこないので意味のないコード
        // 想定外のケースも考慮に入れる
        System.out.println("trueもfalseも帰ってこなかった場合。");
    }

    System.out.println("*** String#isEmpty() Sample1 ****");
    if ("".isEmpty()) {
        System.out.println("文字列は空です。");
    }
    String tmp = null;

    System.out.println("*** String#isEmpty() Sample2 ****");
    try {
        if (tmp.isEmpty()) {
            System.out.println("文字列はNULLです。");
        }
    } catch (NullPointerException e) {
        System.out.println("実行するとNullPoineterExceptionで落ちる。");
    }
}

Sample1: 文字列の調査メソッドの解説

  1. "test".equals("tezt")は、"test"と"tezt"を比較している2つの文字列が等しいならifの中に処理が進む
  2. "test".equals("tezt") == falseは2つの文字列を比較した時の返り値がfalseの場合ifの中に処理が進む
  3. str.equals(str2)は変数「str」と「str2」を比較した時の返り値がtrueの場合ifの中に処理が進む
  4. "test".equalsIgnoreCase("tezt") == falseは下の内容の処理を行っているので「大文字小文字の区別無し」で文字列の比較した時の返り値がtrueの場合ifの中に処理が進む ※Stringクラスのソースファイル参照
    public boolean equalsIgnoreCase(String anotherString) {
    return (this == anotherString) ? true
            : (anotherString != null)
            && (anotherString.value.length == value.length)
            && regionMatches(true, 0, anotherString, 0, value.length);
    }
  5. "test".equalsIgnoreCase("Test")は"test"と"Test"を比較した時の返り値がtrueの場合ifの中に処理が進む
  6. "".isEmpty()は""が空文字だった場合ifの中に処理が進む
  7. String tmp = null;<code>は変数</code>tmpにNULLを代入している、この変数を参照するとNullPointerExceptionで落ちる
  8. try { 何かの処理 } catch ( キャッチする例外 ) { 例外時の処理 }で例外が起きた時の処理を行う。

Sample2 1-2 文字列検索メソッドを利用した例

※クラス全体ではなく、メソッド部分のみを記述します。

使用メソッド一覧
String#contains()
String#endsWith()
String#indexOf()

/**
 * 文字列調査(文字列が等しいか?)のサンプル。
 * 「リスト1-2 文字列検索メソッドを利用した例」
 */
public void sample1_2StringSearch() {
    String str = "0123456789ABCABC";
    System.out.println("*** String#contains() Sample1 ****");
    if (str.contains("012")) {
        System.out.println(str + "は「012」を含んでいます。");
    }
    System.out.println("*** String#contains() Sample1 ****");
    if (str.contains("014")) {
        System.out.println(str + "は「014」を含んでいます。");
    } else {
        System.out.println(str + "は「014」を含んでいません。");
    }

    System.out.println("*** String#endsWith() Sample1 ****");
    if (str.endsWith("ABC")) {
        System.out.println(str + "は「ABC」を末尾にあります。");
    }

    System.out.println("*** String#endsWith() Sample1 ****");
    System.out.println(str + "は「ABC」の文字列が" + str.indexOf("ABC") + "番目に出現します。");
    System.out.println(str + "は「ABC」の文字列が最後に出現するのは" + str.lastIndexOf("ABC") + "番目に出現します。");
}

文字列検索メソッドの解説

  1. str.contains("012")で文字列strに"012"が含まれているか検証しています。含まれているならばtrueを返します。そうでない場合はfalseを返す
  2. str.endsWith("ABC")で文字列strの末尾に"ABC"があるか検証しています。末尾にあればtrue, なければfalseを返す。
  3. str.indexOf("ABC")で文字列str内の"ABC"がはじめに出現する位置(int型)を返します。
  4. str.indexOf("ABC")で文字列str内の"ABC"が最後に出現する位置(int型)を返します。

正規表現を使う

上に記載したもの以外にも、よく使うメソッドを紹介します。

String#matchies()です。

このメソッドは、引数に正規表現を渡して、その正規表現にマッチするならtrue, そうでないならfalseを返します。

正規表現は後々に学習します。とりあえずは下の「数字」とaからz、AからZまでの文字にマッチするケースです。

チェック処理なので、静的メソッドにしています。

public static boolean isNumber(String numberStr) {
    // numberStr0から9のうちどれかに該当するか判定します。(1文字だけ)
    if (numberStr.matches("[0-9]")) {
        return true;
    }
    return false;
}

上の処理は、numberStrが数字1文字で、0から9に該当するかどうかの判定を行なっています。

文字数を複数にする場合は後ろに、「{2,5}」のようにつけると「2桁から5桁の間の0から9の数字」というような意味になります。

関連ページ

Java クラスの扱い〜役割分担をする〜

イントロダクション

オブジェクト指向の理解をするのに、以下の様なステップを踏むと理解しやすいであろうというものです。

クラスの役割分担をする

以前作成したJava ミニゲーム ソース 〜じゃんけんゲーム in Console 〜を作るのにクラスの役割分担を考えます。

CommandIF(インタフェース)を使用したポリモーフィズムの実行動画があります。

単純に以下の様な分担を思いつくかもしれません。

  • メインメソッドを持つクラス
  • じゃんけんゲームを起動するクラス
  • じゃんけんの入力やCPUの手を取得などのユーティリティクラス
  • 入力チェッククラス
  • コンソール表示を行うクラス

全部で5クラスを使うアイデアが出ました。人によりアイデアは違うのでどんな分担がベストなものか議論してみるのも楽しいかもしれません。

## ソースを眺めてみる
[上記のリンク先](https://zenryokuservice.com/wp/2020/06/12/java-%e3%83%9f%e3%83%8b%e3%82%b2%e3%83%bc%e3%83%a0-%e3%82%bd%e3%83%bc%e3%82%b9-%e3%80%9c%e3%81%98%e3%82%83%e3%82%93%e3%81%91%e3%82%93%e3%82%b2%e3%83%bc%e3%83%a0-in-console-%e3%80%9c/)は下のようなクラス構成になっています。
* **Mainクラス**:メインメソッドを持っているクラス
- 「exe」と入力するとFirstCls#execute()が起動する
* **FirstClsクラス**:各処理を実装しているクラス

上記のリンク先で作成したものは、ちょっと面倒な起動の仕方をしています。じゃんけんゲーム他にも何か実装しようとしたためです。

## 役割分担の効果
ここで我々人間がみんなで作業をするときに行う「役割分担」をプログラム上で行うことを考えて見ます。
上のように、「メインメソッドを起動するクラス」と「各処理を実装しているクラス」を作成して、**作業を分担**しました。

## 分担することでできること1
### <インターフェースの追加実装>
これは、単純に分けただけですが、メインメソッドの実装をしたのように変更したとします。 ※FirstClsの実装も変える必要があります。
**ExeInterface**を作成し、FirstClsクラスに実装(implements)します
<作成するインターフェース>
```java
public interface ExeInterface {
// 抽象メソッド(implementsしたクラスに実装を強制する)
public execute(Scanner scan);
}
```

<FirstClsにimeplementsする>
```java
public class FirstCls implements ExeInterface {
// 中身は省略
}
```

```java
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String input = scan.next();

ExeInterface first = new FirstCls();
if ("exe".equals(input)) {
first.execute(scan);
}
boolean isNumber = first.isNumberString(input);
if (isNumber) {
System.out.println(input + "は数字です。");
} else {
System.out.println(input + "は数字ではありません。");
}
}
}
```

このような形にすることで、「FirstClsのじゃんけんゲームではなく、別のゲームを起動したい」と思った時に、FirstClsと同様に「ExeInterfaceを実装」してSecondClsを作成したとします。
メインメソッドも下のように修正します。

```java
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String input = scan.next();

ExeInterface second = new SecondCls();
if ("exe".equals(input)) {
second.execute(scan);
}
boolean isNumber = first.isNumberString(input);
if (isNumber) {
System.out.println(input + "は数字です。");
} else {
System.out.println(input + "は数字ではありません。");
}
}
}
```

このように修正することで、SecondCls#execute()を実行できるようになります。ちなみに修正した部分は2行です。

## さらに、ポリモーフィズムする
インターフェースを作成したことで、簡単に起動するクラスを変更できるようになりました。
しかし、メインメソッドをいちいち修正するのも面倒なので、動的に起動するクラスを追加できるようにしたいと思います。
同じような実装として[「CommandIF」というインターフェースを作成して、使用したときの記事](https://zenryokuservice.com/wp/2020/10/05/java-basic-%e3%80%9c%e3%82%a4%e3%83%b3%e3%82%bf%e3%83%bc%e3%83%95%e3%82%a7%e3%83%bc%e3%82%b9%e3%81%ae%e6%89%b1%e3%81%84%e6%96%b9%ef%bc%92%e3%80%9c/)もありますので参考までにどうぞ。

### ここでの問題1
**メインメソッドの中で「new XXXX」というコードを書くと、起動するクラスを動的に変更できない。**

という問題がありますので、この部分を動的に変更できるようにします。テクノロジーとしては「リフレクション」というものを使用します。Javaパッケージとしては「[java.lang.refrect](https://docs.oracle.com/javase/jp/6/api/java/lang/reflect/package-summary.html)」になります。

#### 具体的に。。。
1. 起動するクラスを動的に変更するために入力によって起動するクラスを取得するように修正
2. 入力値をキーにして、取得するクラスの完全修飾名を取得する
3. 完全修飾名より、起動するクラスのインスタンスを生成、取得する

大まかに上記のような手順で実装します。
##### 1. 起動するクラスを動的に変更するために入力によって起動するクラスを取得するように修正
これは単純に入力値によって条件分岐すれば良いです。

##### 2. 入力値をキーにして、取得するクラスの完全修飾名を取得する
キーと値をセットで動的に取得する、ということを考えると「プロパティファイル」を使用すると楽です。
コードとしては、下のように実装すると、プロパティファイルを読み取ることができ、プロパティファイルは追加したいクラスのキーと値をセットにして追記してやれば良いです。

<プロパティファイルの例>
```
first=jp.zenryoku.sample.FirstCls
second=jp.zenryoku.sample.SecondCls
third=jp.zenryoku.sample.ThirdCls
```

<プロパティファイルを読み取る例>
```java
/** コンストラクタ */
public Lv3_1_RefactorLv2() {
commandList = new ArrayList<String>();
prop = new Properties();
// 現在位置の状態を保持するマップ
placeInfo = getInfoMap();
try {
// resources/
prop.load(getClass().getResourceAsStream("/test.properties"));
} catch (IOException e) {
e.printStackTrace();
// エラーコード-1をセットしてプログラム終了
System.exit(-1);
}
}
```

<プロパティファイルのキーから値を取得する例>
```java
/**
* プロパティファイルから値が取得できた、値を返し
* 取得できない時はから文字("")を返す
* @param inStr キー(コマンド)
* @return プロパティファイルの値
*/
public String getPropertes(String inStr) {
String value = prop.getProperty(inStr);
if ("".equals(value)) {
listPropertyKeys();
return "";
}
return value;
}
```

上のようなメソッドを実装して、プロパティファイルのキーから値(クラスの完全修飾名)を取得します。

##### 3. 完全修飾名より、起動するクラスのインスタンスを生成、取得する
このサンプルコードは、インターフェースとして作成した「CommandIF」を使用していますが、他のインターフェースの場合は「CommandIF」を他のインターフェース型に変更してやれば良いです。

#### リフレクションの実装
そして、ポイントになるのは

Class.forName(fullClassName);

の部分です、リフレクションの実装になります。クラスの完全名からクラスオブジェクトを取得、インスタンスの生成。というような処理を行います。
```java
CommandIF cmd = null;
try {
@SuppressWarnings("unchecked")
Class<CommandIF> cmdCls = (Class<CommandIF>) Class.forName(fullClassName);
cmd = cmdCls.newInstance();
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
System.exit(-1);
}
```
ポイントとしては、完全修飾名の「fullClsName」を引数にクラスオブジェクトを取得(Class#forName())してからインスタンスを生成(Class#newInstance())しているところです。

この処理で生成したクラスを返却してやれば、動的に「CommandIF」を実装したクラスを実行することができます。

## まとめ
役割分担すると「ポリモーフィズム」が使いやすいということです。

<サンプル動画>

## 関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

## JavaFX関連ページ
1. [Eclipse SceneBuilderを追加する](https://zenryokuservice.com/wp/2018/11/17/eclipse-scenebuilder%e3%82%92%e8%bf%bd%e5%8a%a0%e3%81%99%e3%82%8b/)
1. [JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~](https://zenryokuservice.com/wp/2018/11/17/javafx-scenebuilder-%e3%80%9ceclipse%e3%81%a8scenebuilder%e9%80%a3%e6%90%ba/)
1. [JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜](https://zenryokuservice.com/wp/2019/02/05/javafx-scenebuilder%e3%80%9c%e3%83%9c%e3%82%bf%e3%83%b3%e3%81%ab%e3%83%a1%e3%82%bd%e3%83%83%e3%83%89%e3%82%92%e5%89%b2%e3%82%8a%e5%bd%93%e3%81%a6%e3%82%8b%e3%83%af%e3%83%b3%e3%83%9d%e3%82%a4%e3%83%b3/)
1. [Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜](https://zenryokuservice.com/wp/2020/03/30/java-%e3%83%97%e3%83%ad%e3%82%b3%e3%83%b3%e3%82%b2%e3%83%bc%e3%83%a0-%e3%80%9c%e8%a6%8b%e3%81%9f%e7%9b%ae%e3%81%ae%e4%bd%9c%e6%88%90scenebuilder%e3%81%ae%e4%bd%bf%e7%94%a8%e3%80%9c/)

## ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

## JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

## オブジェクト指向関連ページ
1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
1. [オブジェクト指向の概念2〜クラスとは〜](https://zenryokuservice.com/wp/2019/10/30/%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5%e3%80%9c%e3%82%af%e3%83%a9%e3%82%b9%e3%81%a8%e3%81%af%e3%80%9c/)

Java Discord

  1. IntelliJ IDEA Discord Botを作る〜Gradle環境のセットアップ〜
  2. Java Discord セットアップ〜Hello Discord〜
  3.  Java Discord ピンポン〜Discordプログラム〜
  4. Java Discord Listener実装〜コマンドを好きなだけ追加しよう〜

## 設計
1. [設計を始める〜1.アプリイメージ〜](https://zenryokuservice.com/wp/2018/10/25/%e8%a8%ad%e8%a8%88%e3%82%92%e5%a7%8b%e3%82%81%e3%82%8b/)
1. [設計を始める〜2.機能イメージ〜](https://zenryokuservice.com/wp/2018/10/25/%e8%a8%ad%e8%a8%88%e3%82%92%e5%a7%8b%e3%82%81%e3%82%8b%e3%80%9c2-%e6%a9%9f%e8%83%bd%e3%82%a4%e3%83%a1%e3%83%bc%e3%82%b8%e3%80%9c/)
1. [設計を始める〜3.機能概要〜](https://zenryokuservice.com/wp/2018/10/26/%e8%a8%ad%e8%a8%88%e3%82%92%e5%a7%8b%e3%82%81%e3%82%8b%e3%80%9c3-%e6%a9%9f%e8%83%bd%e6%a6%82%e8%a6%81%e3%80%9c/)
1. [Java はじめて16 〜クラス設計から実装〜](https://zenryokuservice.com/wp/2019/09/19/java-%e3%81%af%e3%81%98%e3%82%81%e3%81%a616-%e3%80%9c%e3%82%af%e3%83%a9%e3%82%b9%e8%a8%ad%e8%a8%88%e3%81%8b%e3%82%89%e5%ae%9f%e8%a3%85%e3%80%9c/)

Java Basic 〜インターフェースの扱い方 CommandIF〜

インターフェースの扱い方

java.util.Listやjava.util.Mapのインターフェースを使用することは多いと思います

今回は、自作したインターフェースを使用してみようと思います。

==<今回のやりたいこと>===
自作したインターフェースを使用して、起動するクラスを切り替えて実行しようというものです。

具体的には、インターフェースCommandIFを作成し、以下の2つのクラスに実装、メインメソッドで標準入力を受けて入力した文字列によって2つのクラスのうちどちらを起動するか選択できるようにする。

  1. HelloCommand
  2. ReadyCommand

起動した時の動画です。

インターフェースサンプルを作る

  1. まずはインターフェースクラスを作成します。
    下のように、インターフェースを定義

    public interface CommandIF {
    }
  2. インターフェースに、実装クラスで起動するメソッドを定義します。
    ここで作成するメソッドは、実装(implements)したクラスで必ず定義しなくてはいけないメソッドになります。

    public interface CommandIF {
    /** コマンドを実行する */
    public void execute();
    }

    完成したコードはGithubにあります。

  3. インターフェースを実装する
    今回は下のように2つのクラスに実装(implements)しました。

<メインメソッドで実行する>

public class Lv3_1_RefactorLv2_Main {
    /** コマンドリスト */
    private static  Map<String, CommandIF> cmdMap;
    public static void main(String[] args) {
        // コマンドの用意
        cmdMap = new HashMap<String, CommandIF>();
        cmdMap.put("hello", new HelloCommand());
        cmdMap.put("ready", new ReadyCommand());
        // 標準入力
        Scanner input = new Scanner(System.in);

        while(true) {
            System.out.println("入力してください: ");
            String inStr = input.nextLine();
            if ("bye".equals(inStr)) {
                System.out.println("Good Bye");
                break;
            }

            CommandIF cmd = cmdMap.get(inStr);
            if (cmd != null) {
                cmd.execute();
            } else {
                System.out.println("コマンドが登録されていません。: " + inStr);
            }
        }
    }
}

上のメインメソッドでは、以下のような処理を行っています。

  1. HashMapのインスタンスをMap型の変数に代入
  2. マップのキーに"hello"、値に「HelloCommand」クラスのインスタンス
  3. 同様にキーに"ready"、値に「ReaddyCommand」クラスのインスタンス
  4. 無限ループを開始
  5. 入力を促し、標準入力を受ける
  6. マップから「HelloCommand」か「ReaddyCommand」もしくはnullを取得する(キーに該当するものがないときはNULLが返ってくる)
  7. 「HelloCommand」か「ReaddyCommand」のexecute()メソッドを実行

「HelloCommand」と「ReaddyCommand」クラスには「CommandIF」をimplementsしていますので必ず「execute()」メソッドが存在し、実行することができます。
このように、インターフェースを実装したクラスはそのインターフェース型として使用することができますので、CommandIFを実装(implements)したクラスは全て「execute()」メソッドがあり、CommandIF型の変数に代入、execute()を実行できるというわけです。

余談ですが、このインsターフェースを実装した他のサンプルもありますので、これも紹介します(動画ですが。。。)。

<応用編>

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

でわでわ。。。

関連記事

関連ページ一覧

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

JavaFX関連ページ

  1. Eclipse SceneBuilderを追加する
  2. JavaFX SceneBuilder 〜EclipseとSceneBuilder連携~
  3. JavaFX SceneBuilder〜ボタンにメソッドを割り当てるワンポイント〜
  4. Java プロコンゲーム 〜見た目の作成(SceneBuilderの使用)〜

ステップアップ関連ページ一覧

  1. Java 初めてでも大丈夫〜ステップアッププログラミングのススメ〜
  2. ステップアッププログラミング〜Java FxでHelloWorld解説〜
  3. Java StepUpPrograming〜JavaFX で四則計算〜
  4. Java StepUpPrograming〜JavaFXで画面切り替えを作る1〜
  5. Java StepUpPrograming〜JavaFXで画面切り替え2ボタン作成〜
  6. Java StepUpPrograming〜JavaFXで画面切り替え3アクション〜
  7. Java StepUpPrograming〜JavaFXで画面切り替え4Pane切り替え〜
  8. Java StepUpPrograming〜JavaFXで画面切り替え5WebEngine

JavaFX + ND4Jで機械学習準備

  1. JavaFX + ND4J〜数学への挑戦1:ND4Jのインストール〜
  2. JavaFX + ND4J〜数学への挑戦2: 行列の計算〜
  3. Java + ND4J 〜数学への挑戦3: ベクトル(配列)の作成方法〜

オブジェクト指向関連ページ

  1. [オブジェクト指向の概念1〜OracleDocのチュートリアル1〜](https://zenryokuservice.com/wp/2019/10/301. /%e3%82%aa%e3%83%96%e3%82%b8%e3%82%a7%e3%82%af%e3%83%88%e6%8c%87%e5%90%91%e3%81%ae%e6%a6%82%e5%bf%b5-%e3%80%9coracledoc%e3%81%ae%e3%83%81%e3%83%a5%e3%83%bc%e3%83%88%e3%83%aa%e3%82%a2%e3%83%ab%ef%bc%91/)
  2. オブジェクト指向の概念2〜クラスとは〜