Java はじめて15 〜クラス型変数の使い方〜

イントロダクション

Javaはクラスをプログラムの単位としています。具体的にはJavaのプログラムを起動するのには下のようなコマンドを実行します。

java クラス名[プログラム引数]

つまり、プログラムを実行するのに「クラス」が必要なわけです。正確にはクラス内にある「メインメソッド」を検索して実行するのですが、「クラスが基本単位なんだな」という理解で十分です。

そして、クラスに役割を与えてそれぞれの役割でプログラムを実行するように作成すれば、デバック、プログラムの改修が楽になります。つまりより良いプログラムが作成しやすくなります。

クラスの扱い方イメージ

イメージとしては、演劇を考えるとわかりやすいかもしれません。
例えとして、役者一人一人が「クラス」であり、それぞれの演目の役(役割)を果たすことで「物語をリアルに再現できる」というのが「実行結果」になります。

今回の学習ポイント

今回は、クラスを使うための学習、練習を行います。なのである部隊の役者を一人引っ張って着て「~やって!」と指示するようなイメージです(笑)

プログラムでクラスを使うときには、以前学習したように基本的にはインスタンス化して実行することが多いです。
なので、変数にインスタンスをセットして実行します。

自作のクラスを使う場合はこんな感じでした。

public class Sample1() {
    public static void main(String[] args) {
        Sample1 main = new Sample1();
        main.hello();
    }
    public void hello() {
        System.out.println("Morning!");
    }
}

クラス変数の使い方

Javaで作成したクラスを使う方法を記載します。クラス・インスタンスの作成は、以下のようにコードを書くと作れます。今回の内容はクラス名 変数名 = new クラス名();のように使用するときの話です。

クラス定義の書き方
フィールド変数は「カプセル化」の観点から「private」にしましょう。もし「クラス変数.フィールド変数名」のように操作したいときは「public」にしてやればよいのですが、セキュリティ的によろしくないのでフィールド変数にアクセスるときは「getter, setter」を使いましょう。

/**
 * クラスのJavaDoc
 */
public クラス名 {
    // フィールド変数
    public String  firstName;
    // publicは外部から参照可能
    public int age;
    // privateは外部から参照できない
    private int zako;
    /**
    * メインメソッドのJavaDoc部分
    */
    public static void main(String[] args) {
        // メインメソッド(クラスのメンバメソッドではない)
    }
    /** メンバメソッドのJavaDoc */
    public void menberMethod() {
        // メンバーメソッド(newすると使える)
    }
}

クラス変数

今回は、作成したクラスの中にメインメソッドを作り、自分のクラスを変数に代入して使用します。
下にサンプルコードを示します。

  • データ型:プリミティブ型・参照型を含めて変数の型を意味します。例:「int型、String型、(作成した)Sample1型」

<通常の変数の書き方>

データ型 変数名の形で書く、SampleCls型の変数mainを宣言する
SampleCls main;

<クラスをインスタンス化して変数にセット>

同様に、初期化する場合
SampleCls main = new SampleCls();

サンプルコード1: メンバメソッドについて

クラスをインスタンス化して使用するときに呼び出すメソッドは基本的に「メンバメソッド(インスタンスメソッド)」です。
他にもstaticメソッドとかありますが、呼び名が複数あるので「static」のついたメソッドとそうでないメソッド(通常のメソッド)があると思っていただければよろしいと思います。

/**
 * クラスのJavaDoc
 */
public SampleCls {
    // フィールド変数
    public String  firstName;
    public int age;
    // これは外部から参照できない
    private int zako;
    /**
    * メインメソッドのJavaDoc部分
    */
    public static void main(String[] args) {
        // メインメソッド(クラスのメンバメソッドではない)
        // クラス型の変数main: データ型 変数名の形で書く
        SampleCls main = new SampleCls();
        main.menberMethod();
    }
    /** メンバメソッドのJavaDoc */
    public void menberMethod() {
        // メンバーメソッド(newすると使える)
        System.out.println("Hello MemberMethod!);
    }
    /** staticメソッド */
    public void staticMethod() {
    // クラス名.メソッド名で呼び出せる ※クラスに一つだけ定義できる
        System.out.println("Hello StaticMethod!);
    }
}

<通常のメソッド>

呼び出し方
main.menberMethod();

<staticメソッド>

呼び出し方
SampleCls.staticMethod();

シンプルにこんな形でコードを作成しました。メインメソッドは、「static」がつくので、クラスの中にあっても「new」演算子でのインスタンス化が必要になります。
「書き方」と同じ構成なのでわかりやすいと思いますが、いかがでしょうか?細かい説明は省きますが、メインメソッドの場合は、クラスをnewして使用しないとクラス内のメソッドを使用することができません。これはメンバメソッドはインスタンス化しないと使用できないためです。
逆に、メソッドにstaticをつけてやれば、メインメソッドから使用することができます。

サンプルコード2: staticメソッド

/**
 * クラスのJavaDoc
 */
public SampleCls {
    // フィールド変数
    public String  firstName;
    public int age;
    // これは外部から参照できない
    private int zako;

    /**
    * メインメソッドのJavaDoc部分
    */
    public static void main(String[] args) {
        SampleCls main = new SampleCls();
        // メインメソッド(クラスのメンバメソッドではない)
        main.menberMethod();
        // スタティックメソッドの実行
        staticMethod();
    }

/** メンバメソッドのJavaDoc */
    public void menberMethod() {
        // メンバーメソッド(newすると使える)
        System.out.rintln("Hello MemberMethod!);
    }

    public static void staticMethod() {
        // スタティックメソッド
        System.out.rintln("Hello StaticMethod!);
    }
}

つまりメインメソッド(staticメソッド)以外のメソッドにはクラスをnewしないとアクセスできません。

理屈としては、メインメソッドはstaticメソッドなので、通常のメソッド(メンバ・メソッド)とは独立したメンバ(クラスの要素)になります。

staticとメンバについて

メンバ・メソッドと同様にメンバ・変数というのもあります。フィールド変数の事です。「メンバ」といいう言葉は、JavaだけでなくC言語、それに連なる言語でよく使用されます。

「メンバ」とはクラスの中に定義するフィールド変数とメソッドの事です。ただし、staticと修飾子が付くと話は変わります。

メンバはクラスのインスタンスを生成して使用するルールになっていますが、staticメソッドはクラスのインスタンスを必要としません

なので呼び出し方が下の様に別にになります。ここがインスタンスとオブジェクトの違いになります。※深く考える必要はありません。後々に学びます。

/** サンプルメソッド */
public void sample() {
    ClassA clsA = new ClassA();
    // メンバメソッド
    clsA.memberMethod();
    // staticメソッド
    ClassA.staticMethod();
}

クラスからクラスを呼ぶ

上のコードともう1つ作成して見ます。

public SecondSampleCls {
    // フィールド変数
    public String  firstName;
    public int age;
    // これは外部から参照できない
    private int zako;
    /** JavaDoc */
    public void secondMethod() {
        // メンバーメソッド(newすると使える)
        System.out.rintln("Hello MemberMethod!);
    }
}

はじめのクラスに「メインメソッド」がないだけの同じうようなクラスです。
そして、はじめのクラスをちょっと修正します。

public SampleCls {
    // フィールド変数
    public String  firstName;
    public int age;
    // これは外部から参照できない
    private int zako;
    /**
    * JavaDoc部分
    */
    public static void main(String[] args) {
        // メインメソッド(クラスのメンバメソッドではない)
        SampleCls main = new SampleCls();
        main.menberMethod();
        SecondSampleCls second = new SecondSampleCls();
        second.sendMethod();
    }
    /** JavaDoc */
    public void sendMethod() {
        // メンバーメソッド(newすると使える)
        System.out.rintln("This is SecondMethod!);
    }
}

このような形でメインメソッドから他の作成したクラスを呼び出します。当然java.lang.XXXのようなクラスもこれと同じようにメソッドを呼び出し使用することができます。

String(文字列)クラスを使ってみる

例えば、以下のコードはjava.lang.Stringクラスの「equals()」を使用しています。

public static void main(String[] args) {
    String str = "test";
    if ("test".equals(str) {
        System.out.println("testです");
    } else {
        System.out.println("testではありません");
    }
}

<復習用動画>

<注意点:リテラルを意識しましょう>

  • 「"(ダブルクォーテーション)」で囲った文字はStringクラスとみなされます。
  • 「'(シングルクォーテーション)」で囲った文字はchar型とみなされます。
  • 何もつけない「1」は数値としてみなされます。
String str = "文字列(String)";
char ch = 'も'; // 1文字のみ
int num = 1; // 数値

こんな感じです。

JavaAPIを使ってみる

「JavaAPI」というのは、JDKにい含まれているJavaのクラス群のことです。パッケージ名で言うならば以下のようなもののことです。

  • java.lang.*;
  • java.util.*;
  • java.nio.*;

詳細はこちらのオラクルのJavaaDovページを参照ください。
クラスパッケージはこちらです。

File読み込み処理

クラスの扱い方の一歩目として、File読み込み処理を学習します。
文字列や、配列(リスト)などは、すぐになれると思いますので、まずは飛ばします。

File IO(ファイル入出力)

このファイル入出力処理は、データ(文字列や配列)の扱いと少し違います。以下の操作を行うときには「ストリーム」を使用します。

  • ファイルを開く
  • データを読み込む
  • データをファイルに書き込む

ストリームという言葉

このストリームという言葉は、動画配信などで使用する「ストリーミング」とは別物です。
こちらのページによると下のような意味が書かれていました。

ストリームとは、小川、流れ、連続などの意味を持つ英単語で、ITの分野では連続したデータの流れや、データの送受信や処理を連続的に行うことなどを意味する。

ここでの「ストリーム」とは「プログラムとファイルの間を行き来するデータの流れる道」のことです。
なので、「ストリームを開く」とか「ストリームを閉じる」などというものの言い方をします。
ファイルの読み込みを行うときには、「ストリームを開きファイルにアクセス」してデータを読み取ります。また、読み込みや書き込みが終わったら「ストリームを閉じます。

ファイル読み込み処理

ファイル読み込み処理を実装してみます。ゲームっぽく入力 -> 表示を繰り返す形のプログラムを作りました。
このプログラムは「file」と入力すると「resources/FirstStage.txt」を開き、ファイルを読み込み、記述している内容を出力するというものです。

プログラムコードは下のようなものです。「readFile()」メソッドががいるの読み込み処理を実装したものです。
クラスの中で、ストリームを開くとか閉じるなどの処理を行っているので、プログラム上ではストリームを開くなどの処理を行っています。
なので、プログラム的には次のような形の説明ができます。

  • <ストリームを開く>:new File(fileName);の部分で引数に渡されている「resources/FirstStage.txt」を開く
  • <ファイルを読み込む>: buf.readLine()でファイルを1行ずつ読込む
  • <ストリームを閉じる>: buf.close();でファイルを閉じる(ストリームを閉じる)

使用している、APIはBufferedReaderを主軸にしています。これは、コンストラクタの引数に「Reader」クラスを渡してファイル操作を行う準備をします。詳細はこちらのJavaDocを見てください。

文字、配列、行をバッファリングすることによって、文字型入力ストリームからテキストを効率良く読み込みます。
バッファのサイズは、デフォルト値のままにすることも、特定の値を指定することもできます。デフォルト値は、通常の使い方では十分な大きさです。

一般的に、Readerに対して読込み要求が出されると、それに対応するベースとなる文字型ストリームまたはバイト・ストリームへの読込み要求が発行されます。このため、FileReaderやInputStreamReaderのようにread()オペレーションの効率の良くないReaderでは、その周りをBufferedReaderでラップすることをお薦めします。次に例を示します。

 BufferedReader in
   = new BufferedReader(new FileReader("foo.in"));

筆者が実装したコード

public class NinethProgram {
        public static void main(String[] args) {
            jp.zenryoku.sample.basic.NinethProgram main = new jp.zenryoku.sample.basic.NinethProgram();
            Scanner scan = new Scanner(System.in);

            while(true) {
                System.out.print("入力してください: ");
                String in = scan.next();

                if("bye".equals(in)) {
                    System.out.println("アプリ終了");
                    break;
                }
                String[] tmp = new String[] {"aaa"};
                try {
                    if (in.equals("test")) {
                        System.out.println("*** Testing now! ***");
                    } else if ("file".equals(in)) {
                        main.readFile("resources/FirstStage.txt");
                    } else if (tmp.length == 1) {
                        System.out.println("*** Not Error! ***");
                    }
                } catch (FileNotFoundException e) {
                    System.out.println("*** No File! ***");
                } catch (IOException e) {
                    System.out.println("*** What's up!? ***");
                }
            }
        }
        private void readFile(String fileName) throws FileNotFoundException, IOException {
            File f = new File(fileName);
            BufferedReader buf = new BufferedReader(new FileReader(f));
            String line = null;
            while((line = buf.readLine()) != null) {
                System.out.println(line);
            }
            buf.close();
        }
}

上記のBufrrerdReaderクラスの場合でもそうですがJavaDocにJavaAPIの使い方など全て書かれていますので、それを読んで理解できるようになれば、Javaを極めたといっても過言ではありません

筆者も学習中です。そのほか「デザインパターン」が実装済みのAPIもありますので、眺めてみるのもよいと思います。

でわでわ。。。

<Java関連の動画リスト>

<<< 前回 次回 >>>



投稿者:

takunoji

音響、イベント会場設営業界からIT業界へ転身。現在はJava屋としてサラリーマンをやっている。自称ガテン系プログラマー(笑) Javaプログラミングを布教したい、ラスパイとJavaの相性が良いことに気が付く。 Spring framework, Struts, Seaser, Hibernate, Playframework, JavaEE6, JavaEE7などの現場経験あり。 SQL, VBA, PL/SQL, コマンドプロント, Shellなどもやります。

コメントを残す