今回は、Javaを初めて学ぶ人のために、「オブジェクト指向ってなんだか難しそう…」という壁を楽しく乗り越えるための解説をしていきます!

使うのは、とてもシンプルな数当てゲームです。けれど、このゲームの裏側にはオブジェクト指向のエッセンスがたっぷり詰まっているんです。

さあ、一緒にコードを読み解きながら、Javaの基礎とオブジェクト指向の考え方を身につけましょう!


オブジェクト指向とは?

まず、「オブジェクト指向ってなに?」と思ったかもしれませんね。最初にざっくりイメージをつかみましょう!

オブジェクト指向の基本

オブジェクト指向とは、「現実世界の物事を、プログラムの中で“モノ(オブジェクト)”として扱おう」という考え方です。なお、この研修ではオブジェクトのことをインスタンス(実体)という表現をします。

たとえば、「ペットボトルの水」をプログラムにしたいとき、「水」そのものではなく、

  • 容量(例えば500ml)
  • メーカー(例えばサントリー)
  • 味(例えばレモン味)

のような「性質(=プロパティフィールド)」と、

  • 飲む
  • 開ける
  • 捨てる

のような「行動(=メソッド)」を一緒にした「ひとまとまりのオブジェクト」にします。

このように、プログラムの中で「モノ」ごとにデータと処理をセットにして管理するのが、オブジェクト指向の大きな特徴です。


それでは、用意されたコードを見てみましょう。このコードを暗記するほどに書いて実行してエラーを出して、また書き換えてを繰り返すことで皆さんの力は確実に上がります。どうぞプログラムの素振りだと思って書いてください。

Kazuateクラス

数当ての仕組みをもつ「ゲームの実体」

package chap01;

import java.util.Random;

public class Kazuate {

	private int answer;
	private String message;

	public Kazuate() {
		Random random = new Random();
		this.answer = random.nextInt(10); // 0~9 の乱数
	}

	public void checkAnswer(int guess) {
		if (answer == guess) {
			setMessage("あたり");
		} else if (answer > guess) {
			setMessage("もっと大きいよ");
		} else {
			setMessage("もっと小さいよ");
		}
	}

	public int getAnswer() {
		return answer;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public String getMessage() {
		return message;
	}
}

パッケージとインポート

パッケージ:クラスの収納棚

Windowsのフォルダでクラスの整理に役立ちます。パッケージとは、クラスを整理・管理するためのグループのようなものです。Windowsではフォルダになります。Javaではpackage文を使ってクラスに属するパッケージを指定し、関連するクラス同士をまとめて管理します。

package chap01;

インポート

インポート(import)は、他のパッケージにあるクラスや機能を使うための宣言です。

import java.util.Random;

と書くことで、標準ライブラリのRandomクラスを自分のコード内で利用できるようになります。Randomクラスはその通り乱数を発生させるクラスです。

セミコロンと波かっこ

  • セミコロン( ; ):文の終わりには必ずつけます。英語で言えば「ピリオド」のような役割ですね。
  • 波かっこ( { } ):複数の文(=ブロック)をまとめるときに使います。

なお、インデント(字下げ)はプログラムの実行とは無関係ですが、見やすさのためには重要です。ショートカットキーがありますから講師に尋ねてみてください。

どんな「性質」と「行動」を持っている?

フィールド(変数)

Javaの変数とは、値(データ)を一時的に保存するための名前付きの箱です。変数には型を指定して使い、整数や文字列などを格納できます。プログラム内で値を計算したり、再利用したりする際に活躍します。変数については、この後すぐ「2章. 変数でデータを再利用できるようになる」で詳しく学びます。文字列については、「7章. 文字列を扱ってユーザーにメッセージを伝える」で学びます。

変数にはいろいろな種類がありますが、ここで使われているフィールドはクラスの中で宣言される変数のことを指します。フィールドはクラスが持つ属性や状態を表すための変数で、インスタンスごとに値を保持するのが基本です。

  • answer: 正解の整数値(ランダムで0〜9が入る)
  • message: 結果の文字列(例:「もっと大きいよ」など)

なお、フィールドは一般的にprivateで宣言されます。

Javaの世界では、カプセル化(encapsulation)という考え方があります。これは、「データはクラスの中に閉じ込めて、必要なときだけ取り出すようにしよう!」というルールです。

そのため、answerという変数はprivateで宣言されているのが普通です。このクラス内からしかアクセスできないという意味です。

private int answer;


だから、直接アクセスできず、getAnswer()を通して取得するのが一般的な書き方です。「11章. カプセル化と情報隠蔽で部品の完成度を高める」で詳しく学びましょう。

コンストラクタ(特別なメソッド)

Kazuate()というメソッドは、Kazuateクラスのインスタンスが新しく作られるときに呼ばれる特別なメソッドです。ここで正解の数字(answer)がランダムに決まります。

この中ではまず、Javaが最初から用意しているRandom クラスを使って乱数生成器を作成しています。次に、random.nextInt(10) によって 0から9の間の整数をランダムに1つ生成し、それを answer フィールドに代入しています。this.answer と書くことで、クラス内の変数であることを明示しています。

つまり、この処理は「ゲーム開始時に正解の数字をランダムに決定する」役割を持っています。このようにコンストラクタはインスタンスの初期化処理を担当します。コンストラクタについては、「9章. インスタンスでデータと処理をまとめて再利用可能部品にする」で詳しく学びます。

public Kazuate() {
	Random random = new Random();
	this.answer = random.nextInt(10);
}

メソッド(行動)

Javaのメソッドとは、ある処理をまとめた命令のかたまりで、名前をつけて再利用できる機能です。入力(引数)を受け取り、結果(戻り値)を返すこともできます。コードの整理や再利用に役立ちます。Kazuateクラスには以下の4つのメソッドがあります。

  1. setMessage():メッセージを設定する
  2. checkAnswer(int guess):答えをチェックして、結果のメッセージをsetMessage()でセットする
  3. getAnswer():正解の数字を取得(外から見えるようにする)
  4. getMessage():判定結果のメッセージを取得

順に詳しく解説します。


1. setMessage():メッセージを設定する
	private void setMessage(String message) {
		this.message = message;
	}

このsetMessageメソッドは、引数として受け取った文字列をクラス内のmessageフィールドに代入するためのセッター(setter)メソッドです。

メソッドの引数とフィールドの名前が同じなので、this.messageと書くことでクラスのフィールドであることを明示しています。

private修飾子が付いているため、このメソッドはクラス内部(例えば、次のcheckAnswer()メソッド)からしか呼び出せないという意味です。外部から直接messageを書き換えるのではなく、安全に値を変更するために使われます。

2. checkAnswer(int guess):ユーザーの入力を判定する

このメソッドは、ユーザーが入力した数(guess)を正解(answer)と比較して、メッセージをセットする処理です。

	public void checkAnswer(int guess) {
		if (answer == guess) {
			setMessage("あたり");
		} else if (answer > guess) {
			setMessage("もっと大きいよ");
		} else {
			setMessage("もっと小さいよ");
		}
	}

  • guess は引数と呼ばれメソッドのインプットです。プレイヤーが入力した数字がここに渡されます。
  • answer はこのクラスのフィールドで、正解の数字があらかじめランダムにセットされています。
  • 入力が正解なら "あたり"、小さければ "もっと大きいよ"、大きければ "もっと小さいよ" というメッセージをsetMessage()メソッドを使い message に保存します。

このように、判定ロジック結果の保存を1つのメソッドにまとめることで、処理の流れが整理され、再利用もしやすくなっています。



3. getMessage():判定結果メッセージを取り出す
public String getMessage() {
	return message;
}

このgetMessageメソッドは、クラス内にあるmessageというフィールドの値を外部に取り出すためのゲッター(getter)メソッドです。戻り値の型がStringで、return message;と書かれていることから、現在のmessageの内容がそのまま返されます。

たとえば、判定結果などのメッセージを画面に表示したいときに使います。


メソッドについては、「8章. メソッドを定義して処理を再利用する」で、継承やオーバーライドについては「10章. 継承を使ってクラスをグループ化する」で詳しく学びます。

4. getAnswer():答えを取り出す
public int getAnswer() {
	return answer;
}

このメソッドは、クラス内のanswerフィールドの値を返すゲッター(getter)メソッドです。外部から正解の値を確認したいときに、取得できるように設計されています。


Kazuateクラスのまとめ

この4つのメソッドはそれぞれ独立していますが、うまく連携して1つの流れを作っています。

このように、役割を明確に分けて、外部と内部のやり取りをコントロールする設計が、Javaにおける良いオブジェクト指向の基本です。

ただし、このKazuateクラス単体では実行できません。この後に紹介するKazuateTestクラスがあって初めて実行が可能です。

なぜ、そのように複数のクラスを組み合わせるのでしょうか?

その理由は、Kazuateクラスは今後、様々な使われ方をする部品だからです。現在はコンソールアプリケーションといってキーボードから入力して黒い画面で実行結果が表示されます。しかし、将来的にはWebアプリケーションといってブラウザから入力を受け付け、Webページに出力するようにすることもできます。あるいは、スマートフォンアプリにするかもしれませね。

そこで次にKazuateTestクラスを詳しく見ていくことにします。


KazuateTestクラス:ゲームを実行するプログラム

実際の開発では、すべてのプログラムを1つのクラスにまとめるのではなく、役割ごとに複数のクラスに分けて設計するのが一般的です。

たとえば「数当てゲーム」を作る場合でも、「ゲームのロジックを処理するクラス」「ユーザーの入力を受け取り結果を表示するクラス」など、役割ごとにクラスを分けます。

なぜこんなふうに分けるのか?それはコードの見通しを良くし、管理しやすくするためです。

もしすべての処理を1つのクラスに書いてしまったら、たとえるなら「料理・掃除・洗濯・読書が全部同じ部屋に詰め込まれた家」のような状態になります。すべてが混ざり合っていて、どこに何があるのか分からなくなりますよね。

一方、クラスを適切に分ければ、「キッチン」「リビング」「書斎」などのように目的別に整理された空間になります。変更が必要になったときも、どのクラスを直せばいいのかが明確になりますし、バグも見つけやすくなります。

さらに、他の人と協力して開発する際にも、クラスごとに作業を分担できるというメリットがあります。「私は表示の部分を担当します」「あなたはゲームのルール部分をお願いします」といった形で、効率よく作業を進められるのです。


このように、Javaでは複数のクラスに分けてプログラムを作るのが基本であり、むしろそれが読みやすくてメンテナンスしやすいプログラムを作るコツでもあります。

以下のKazuateTestは「ユーザーの入力を受け取り結果を表示するクラス」です。

このクラスはmain()メソッドだけがあります。メインメソッドは、その名の通りJavaプログラムの実行開始点となる特別なメソッドです。形式は必ずpublic static void main(String[] args)で書き、ここから他の処理やクラスが呼び出されてプログラムが動き出します。

package chap01;

import java.util.Scanner;

public class KazuateTest {
	public static void main(String[] args) {

		System.out.println("0-9の整数で数を当ててください!"); //①
		Scanner sc = new Scanner(System.in); //②
		int guess = sc.nextInt(); //②
		sc.close();

		Kazuate game = new Kazuate(); //③
		game.checkAnswer(guess); //④

		System.out.println(game.getMessage()); //⑤
		System.out.println("答えは " + game.getAnswer()); //⑥
	}
}

何が行われているのか順に追ってみよう

  • ①ユーザーに「数字を入力して」と表示しているのは何行目ですか?
あなたの答え:
  • ②Scannerというクラスを使って、キーボードから数字を読み取っているのは何行目ですか?
あなたの答え:
  • ③Kazuateクラスのインスタンスを1つ作り(このとき、ランダムな答えが決まる!)インスタンスをKazuate型の変数gameに代入しているのは何行目ですか?
あなたの答え:

(この変数名は何でもよいがkazuateやgameのようにわかりやすい名前を付ける)

  • ④入力された数字をcheckAnswer()に渡して、結果を判定しているのは何行目ですか?
あなたの答え:
  • ⑤メッセージを表示(例:「もっと大きいよ」など)しているのは何行目ですか?
あなたの答え:
  • ⑥正解を表示しているのは何行目ですか?
あなたの答え:


図でイメージを整理しよう!

新人エンジニア


このゲームで学べるオブジェクト指向のポイント

クラスはJavaの”家”のようなもの

Javaのすべてのコードは「クラス」の中に書かなければなりません。
クラスとは、機能やデータをまとめた「設計図」のようなものです。

public class Hello {
    public static void main(String[] args) {
        System.out.println("0-9の整数で数を当ててください!");
    }
}

このように、クラスの中にmainメソッドを作って、そこがプログラムの「スタート地点」となります。
このmainメソッドは、次のように書くのがルールです。

public static void main(String[] args)

この部分、最初は覚えるしかないですが、慣れれば自然と手が動くようになります!IDEを使っている場合はコード補完が効きますので、講師に尋ねてください。


データ型と変数:箱に何を入れるかをはっきりさせる!

Javaは「静的型付け言語」と呼ばれています。つまり、変数を使うときに「どんな種類のデータなのか」を必ず指定する必要があります。

たとえば:

int age = 18;

int guess = sc.nextInt();

この場合、ageやguessは「int型(整数)」です。「整数専用の箱」を用意しているということになります。



制御構文と演算子:プログラムに選択肢や繰り返しを与える

条件分岐:if文

条件分岐とは、ある条件に応じて処理を変える仕組みです。Javaではifなどを使って実装します。たとえば「点数が60以上なら合格、それ以外は不合格」といった判定を行う際に使われます。

	public void checkAnswer(int guess) {
		if (answer == guess) {
			setMessage("あたり");
		} else if (answer > guess) {
			setMessage("もっと大きいよ");
		} else {
			setMessage("もっと小さいよ");
		}
	}

なお、==で等しいという演算子、=は代入という意味ですのでしっかり区別しましょう。

なお、演算子と条件分岐についてはそれぞれ、「3章. 演算子でプログラムに計算させる」、「4章. 条件分岐で場合に応じた処理ができるようになる」で詳しく学びます。


オブジェクト指向の基本:クラスとインスタンス

Javaはオブジェクト指向言語です。

ちょっと難しく聞こえるかもしれませんが、たとえば「設計図(クラス)」を元に「実体(オブジェクト)」を作るイメージです。

Scanner sc = new Scanner(System.in);

Kazuate k = new Kazuate();

このように、newを使ってインスタンス(実体)を作成します。

メソッドとは?

メソッドはシステムの最小単位です。システムとはIPOすなわち(Input Process Output)を備えているものです。


メソッドの一覧

メソッド名引数(型と名前)戻り値の型役割
checkAnswer(int guess)int guess(ユーザーの予想)void(戻り値なし)入力された数(予想)を正解と比較し、結果メッセージを設定する
getAnswer()なしint(整数)正解の数(answer)を外部に公開する
getMessage()なしString(文字列)直前のチェック結果("あたり"など)を取得して表示するために使う

引数(パラメータ)って何?

メソッドの括弧の中にある部分が「引数(パラメータ)」です。
これは、メソッドに外からデータを渡す手段です。

たとえば、

checkAnswer(5);

と呼び出すと、guess には 5 という整数が渡されます。
それを使って、answerと比較し、結果のメッセージをmessageという変数に保存します。


戻り値とは?

メソッドが何を返すか(出力するか)を「戻り値」と言います。
checkAnswer()メソッドのように戻り値の型がvoidの場合は、「何も返さない=内部処理だけ行う」という意味です。

一方、getAnswer()やgetMessage()のように戻り値があるメソッドは、外部に結果を渡す用途で使います。

まとめ

ポイント解説
クラス設計図。ここでは Kazuate クラス
インスタンス(オブジェクトとも)実体。new Kazuate() で作る
フィールドオブジェクトの持つデータ。answer, message
メソッドオブジェクトのふるまい。checkAnswer()など
カプセル化データ(フィールド)を外から直接触らせず、メソッド経由で操作させる考え方

この数当てゲームは短いプログラムですが、Javaの基礎とオブジェクト指向の重要な考え方がギュッと詰まっています。

  • クラスとオブジェクトの違い
  • フィールドとメソッドの役割
  • コンストラクタの働き
  • 条件分岐によるロジックの構築

が自然と身につきます。

ただし、プログラミングはテキストを読んでも、講義を聞いても身に付きません。

まずはお手本のコードを書き写して、次に何も見ずに書いて、さらに書き換えてみてください。この数あてゲームのコードを何も見なくても書けるまで毎日練習しましょう!

インプットだけではいけません。必ずアウトプットして学ぶことを心がけてください。

参考:本研修で使用するJavaの記号一覧

新人エンジニアの皆さんは、これまでの生活の中でどの程度記号を意識してきたでしょうか?

以下の記号は決して顔文字を作るためにあるのではありません。ITエンジニアは記号を使いこなすことができなくてはいけません。下表1.1では本研修に出てくる主な記号をご紹介しています。

記号読み方主な用途
=イコール値の代入
==ダブルイコール値の比較
+ - * /足す・引く・かける・割る算術演算
%パーセント・モジュロ割り算の余り
++ --インクリメント・デクリメント値を1つ増減
!=ノットイコール等しくないことの判定
> < >= <=大なり・小なりなど大小比較
&& ||アンド・オア論理積・論理和
!ノット否定
[]かぎかっこ配列、インデックスアクセス
{}波かっこブロック(処理のまとまり)
()丸かっこメソッド、条件文など
;セミコロン命令の終わりを示す
" 'ダブルクオート・シングルクオート文字列、文字のリテラル
// /* */スラッシュ、コメントコメントの記述
@アットマークアノテーションに使う
.ドットメソッドやプロパティの呼び出し

以上、今回は「Java言語の特徴」について見てきました。後々にならないと意味の分からないところも多いと思います。研修をある程度進めてから改めて読むと良いと思います。

次回は、「Javaの変数とデータ型」を学びます。

Java言語を初めて学ぶ新人エンジニアの皆さんへ 最後までお読みいただきありがとうございます。