6日でできる 新Java入門|クラスの定義

クラスの定義を覚えれば、Javaの世界は一気に広がる。設計図を描けるようになると、プログラムはもっと強く、もっと整理しやすくなる。

Javaを学び始めると、String や ArrayList のように、すでに用意されているクラスを使う場面がたくさん出てきます。これらはとても便利ですが、Javaの本当のおもしろさは、自分でクラスを作れるところにあります。

クラスは、データと処理をひとまとまりにして扱うための仕組みです。ドラゴンボールの世界観でたとえるなら、クラスは「戦士の設計図」です。どんな名前を持ち、どれくらいの戦闘力があり、どんな技を使えるのか。そういった情報をひとつにまとめたものがクラスです。

そして、その設計図から実際に生まれる戦士がオブジェクトです。サイヤ人という種族の設計図があり、その設計図をもとに個々の戦士が存在するイメージです。クラスの定義を理解すると、ただ命令を並べるだけではなく、「もの」と「ふるまい」を整理しながらプログラムを組み立てられるようになります。

ここでは、クラスの基本構造、フィールド、メソッド、コンストラクタ、this、アクセス修飾子、カプセル化までを、ドラゴンボール風の世界観でやさしく丁寧に見ていきます。

クラスとは何か

クラスは、データと処理をまとめた設計図です。

たとえば、ただの変数だけで戦士を表そうとすると、名前、戦闘力、必殺技名などを別々に管理することになります。これだと、データが増えたときに整理が大変ですし、どのデータがどの戦士のものなのか分かりにくくなります。

そこでクラスを使います。クラスを使うと、「戦士に関する情報」と「戦士が行う動作」をひとつのまとまりとして表現できます。

ドラゴンボール風に考えると、次のようなイメージです。

考え方内容
クラス戦士の設計図
オブジェクト設計図から生まれた実際の戦士
フィールド戦士の名前や戦闘力などの情報
メソッドかめはめ波を放つ、変身する、自己紹介するなどの動作
コンストラクタ戦士が誕生したときの初期設定

つまり、クラスの定義とは、「どんな情報を持ち」「どんな行動ができる戦士なのか」を決めることです。

クラスの基本構造

Javaでクラスを定義するときの基本形は次のようになります。

public class クラス名 {
    // フィールド
    // コンストラクタ
    // メソッド
}

この形の中に、必要な部品を入れていきます。

クラス宣言

class は、「これからクラスを定義します」と宣言するキーワードです。
public は、このクラスをほかの場所からも使えるようにする修飾子です。

たとえば、サイヤ人の設計図を作るなら、こんな形になります。

public class Saiyan {
}

もちろん、これだけでは中身が空なので、まだ何もできません。ここにフィールドやメソッドを追加していくことで、クラスとして意味のあるものになっていきます。

クラスを構成する3つの基本要素

クラスの中でも特に大切なのが、フィールド、コンストラクタ、メソッドの3つです。

要素役割ドラゴンボール風のたとえ
フィールドデータを持つ戦士の名前、戦闘力、所属など
コンストラクタ初期化を行う戦士が登場した直後の初期設定
メソッド処理を行う技を出す、変身する、状態を表示する

この3つを押さえると、クラスの輪郭がかなりはっきり見えてきます。

フィールドとは何か

フィールドは、クラスが持つデータです。
オブジェクトごとに、それぞれ別の値を持てるのが特徴です。

たとえば、戦士を表すクラスなら、次のようなフィールドが考えられます。

String warriorName;
int battlePower;
String specialMove;

これらはそれぞれ、

  • warriorName は戦士の名前
  • battlePower は戦闘力
  • specialMove は必殺技名

を表します。

フィールドは、クラスが「何を覚えておく存在なのか」を示します。
人でいえばプロフィールのようなものです。

フィールドのイメージ

サイヤ人Aとサイヤ人Bがいたとします。どちらも同じ Saiyan クラスから作られたオブジェクトでも、持っている値は別です。

オブジェクトwarriorNamebattlePowerspecialMove
戦士1レン3500気弾連射
戦士2カイ7200烈風波

同じ設計図から生まれていても、実際の中身はそれぞれ違います。ここがクラスとオブジェクトの大事なポイントです。

コンストラクタとは何か

コンストラクタは、オブジェクトが作られるときに自動で呼び出される特別な処理です。主にフィールドの初期化に使います。

書き方の特徴は次の2つです。

  • クラス名と同じ名前にする
  • 戻り値を書かない

たとえば、Saiyan クラスのコンストラクタはこのように書けます。

public Saiyan() {
    warriorName = "無名の戦士";
    battlePower = 0;
    specialMove = "なし";
}

このコンストラクタがあると、new Saiyan() と書いたときに、自動で初期値がセットされます。

なぜコンストラクタが必要なのか

もしコンストラクタがなければ、オブジェクトを作ったあとに毎回手作業で初期値を入れる必要が出てきます。
それだと、初期化し忘れや設定ミスが起きやすくなります。

コンストラクタを使えば、「このクラスのオブジェクトは、作られた瞬間にこういう状態にしておく」というルールを決められます。

これは、戦士が登場した瞬間に、道着を着ていて、初期戦闘力が設定されていて、基本技が使える状態にしておくようなものです。

メソッドとは何か

メソッドは、クラスに備わる機能や処理です。
「そのオブジェクトが何をできるか」を表します。

たとえば、戦士の情報を表示するメソッドなら、次のように書けます。

public void showStatus() {
    System.out.println("戦士名: " + warriorName);
    System.out.println("戦闘力: " + battlePower);
    System.out.println("必殺技: " + specialMove);
}

このメソッドを呼び出すと、そのオブジェクトが持っている情報を表示できます。

メソッドの見方

メソッドには、次のような要素があります。

部分意味
public外から呼び出せる
void戻り値がない
showStatusメソッド名
()引数の並び
{ ... }実際の処理

メソッド名は、その処理の役割が伝わる名前にするのが基本です。
ドラゴンボール風の世界観なら、showStatus や transformToSuperSaiyan のように、意味が分かる名前にすると読みやすくなります。

サンプルプログラムでクラスの定義を見てみよう

ここでは、戦士の情報を表すクラスを使って、クラスの定義を一通り確認してみます。
名前、戦闘力、必殺技を持ち、情報を表示したり、スーパーサイヤ人化して戦闘力を上げたりする例です。

ファイル名:Saiyan.java

public class Saiyan {
    // フィールド
    private String warriorName;
    private int battlePower;
    private String specialMove;

    // 引数なしコンストラクタ
    public Saiyan() {
        this("見習い戦士", 1000, "気弾");
    }

    // 引数ありコンストラクタ
    public Saiyan(String warriorName, int battlePower, String specialMove) {
        this.warriorName = warriorName;
        this.battlePower = battlePower;
        this.specialMove = specialMove;
    }

    // 戦士の状態を表示するメソッド
    public void showStatus() {
        System.out.println("戦士名: " + warriorName);
        System.out.println("戦闘力: " + battlePower);
        System.out.println("必殺技: " + specialMove);
    }

    // スーパーサイヤ人化するメソッド
    public void transformToSuperSaiyan() {
        battlePower *= 50;
        System.out.println(warriorName + " はスーパーサイヤ人へ覚醒した。");
        System.out.println("戦闘力が大きく上昇した。");
    }

    public static void main(String[] args) {
        Saiyan fighter1 = new Saiyan("悟空", 3200, "閃光波");
        Saiyan fighter2 = new Saiyan();

        System.out.println("初期状態を確認します。");
        fighter1.showStatus();
        System.out.println();

        fighter2.showStatus();
        System.out.println();

        fighter1.transformToSuperSaiyan();
        System.out.println();

        System.out.println("変身後の状態を確認します。");
        fighter1.showStatus();
    }
}

実行結果

初期状態を確認します。
戦士名: 悟空
戦闘力: 3200
必殺技: 閃光波

戦士名: 見習い戦士
戦闘力: 1000
必殺技: 気弾

悟空 はスーパーサイヤ人へ覚醒した。
戦闘力が大きく上昇した。

変身後の状態を確認します。
戦士名: 悟空
戦闘力: 160000
必殺技: 閃光波

このサンプルから分かること

このプログラムには、クラス定義で学びたいポイントがしっかり入っています。

1つのクラスにデータと処理がまとまっている

Saiyan クラスの中には、名前、戦闘力、必殺技というデータがあり、それを表示する showStatus() や、変身する transformToSuperSaiyan() という処理があります。

つまり、戦士に関する情報と動作が、ひとつのまとまりとして管理されています。

オブジェクトごとに中身が違う

fighter1 と fighter2 は、同じ Saiyan クラスから作られていますが、中身は違います。
fighter1 は 悟空、fighter2 は 見習い戦士 です。

これが「同じ設計図から、異なる個体を作れる」というクラスの大きな魅力です。

コンストラクタによって初期値が決まる

fighter1 は引数ありコンストラクタで作られているので、名前も戦闘力も必殺技も指定した値になります。
fighter2 は引数なしコンストラクタなので、あらかじめ決められた初期値が設定されます。

this キーワードを理解しよう

クラスの中でよく出てくるのが this です。
this は「このオブジェクト自身」を表します。

特に、引数名とフィールド名が同じときに大活躍します。

public Saiyan(String warriorName, int battlePower, String specialMove) {
    this.warriorName = warriorName;
    this.battlePower = battlePower;
    this.specialMove = specialMove;
}

このコードでは、左側の this.warriorName がフィールド、右側の warriorName が引数です。

もし this を付けなければ、同じ名前が並んでしまって、どちらがフィールドなのか分かりにくくなります。

this の役割

書き方意味
this.warriorNameこのオブジェクトのフィールド warriorName
warriorNameコンストラクタに渡された引数 warriorName

this は、自分自身をはっきり指し示すための言葉です。
ドラゴンボール風にいえば、「この戦士自身の戦闘力」「この戦士自身の技」と言い分けているような感覚です。

コンストラクタ同士の連携

this は、フィールドを区別するだけでなく、同じクラスの別のコンストラクタを呼び出すときにも使えます。

サンプルプログラムの引数なしコンストラクタは、次のようになっていました。

public Saiyan() {
    this("見習い戦士", 1000, "気弾");
}

この this(...) は、「同じクラスの別のコンストラクタを呼び出す」という意味です。

これによって、初期化の処理を1か所にまとめられます。

なぜ便利なのか

もし引数なしコンストラクタと引数ありコンストラクタの両方に、同じ代入処理を何度も書いていたら、あとで修正が入ったときに両方直さなければいけません。

でも this(...) を使えば、初期化の中心を1つにできます。

これは、修行メニューの基本形をひとつ作っておき、見習い戦士用の初期設定も、そこを呼び出して流用するイメージです。無駄が減って、とても整理しやすくなります。

アクセス修飾子を理解しよう

クラスを定義するときには、どこからアクセスできるかを決めるアクセス修飾子も大切です。

代表的なものは次の3つです。

修飾子意味
publicどこからでもアクセスできる
private同じクラスの中からしかアクセスできない
protected同じパッケージやサブクラスからアクセスできる

public

public は、広く公開するための修飾子です。
クラスやメソッドに付けると、ほかのクラスからも利用できます。

public void showStatus() {
    ...
}

このようにしておけば、別の場所から fighter1.showStatus() のように呼び出せます。

private

private は、クラスの外から直接触らせたくないものに付けます。

private String warriorName;
private int battlePower;
private String specialMove;

これで、外部から勝手に直接変更されるのを防ぎやすくなります。

protected

protected は継承を学ぶときに重要になる修飾子です。
今の段階では、「private より少し広く、public よりは狭い公開範囲」ととらえておけば十分です。

カプセル化とは何か

フィールドを private にして、必要な操作だけを public なメソッドで公開する考え方をカプセル化といいます。

これは、データをむき出しにしないための大切な工夫です。

たとえば、戦闘力を好き勝手に書き換えられる状態だと困ることがあります。
ありえない値が入ったり、ルールに反した変更が行われたりするかもしれません。

そこで、直接いじらせるのではなく、専用のメソッドを通して操作させます。

public class SaiyanGuarded {
    private String warriorName;

    public String getWarriorName() {
        return warriorName;
    }

    public void setWarriorName(String warriorName) {
        this.warriorName = warriorName;
    }
}

カプセル化のメリット

メリット内容
安全性が上がる不正な値の代入を防ぎやすい
修正しやすい内部の作りを外に影響させずに変更しやすい
意図が明確になる何を公開し、何を隠すか整理できる

ドラゴンボール風にたとえるなら、戦士の内部の気の流れを外から直接いじらせず、正規の修行手順や変身手順を通して扱うようなものです。
むやみに触らせないからこそ、安定した設計になります。

オブジェクト指向の考え方をドラゴンボール風に整理しよう

クラスの定義は、オブジェクト指向の入口です。ここは少し抽象的に感じることもあるので、ドラゴンボール風に整理してみます。

オブジェクト指向の用語ドラゴンボール風のたとえ
クラスサイヤ人という種族や戦士の設計図
オブジェクト実際に存在する個々の戦士
フィールド名前、戦闘力、必殺技
メソッド修行する、変身する、技を放つ
カプセル化気の扱いを勝手に触らせず、決められた方法で管理する
コンストラクタ戦士が登場したときの初期設定

このように考えると、クラスは単なる文法ではなく、「現実のものごとをどう整理して表現するか」という考え方そのものだと見えてきます。

クラス定義を書くときに意識したいポイント

クラスの定義を書き始めるときは、いきなりコードを書くよりも、まず次の3つを考えると整理しやすいです。

そのクラスは何を表すのか

まずは、クラスがどんな存在を表すのかをはっきりさせます。
戦士なのか、修行メニューなのか、道具なのか。ここが曖昧だと、中に入れるべきデータや処理もぶれやすくなります。

どんなデータを持つのか

その存在に必要な情報は何かを考えます。
戦士なら、名前、戦闘力、技名などが候補になります。

どんなふるまいをするのか

その存在がどんな行動をするのかを考えます。
表示する、修行する、変身する、攻撃する、回復する、などです。

この3つを意識するだけで、クラス設計はかなりスムーズになります。

図:クラスの基本構造

↓クリックすると拡大表示されます。

この図が示していること

この図は、1つのクラスの中に、フィールド、コンストラクタ、メソッドという主要要素がまとまっていることを示しています。さらに、その設計図から複数のオブジェクトが作られ、それぞれ別の値を持てることも表しています。

この図から分かること

クラスはただの箱ではなく、データと処理をひとまとめにした設計図であることが分かります。また、同じクラスから作られたオブジェクトでも、中身は個別に異なることが分ります。

図:this とコンストラクタの連携

↓クリックすると拡大表示されます。

この図が示していること

この図は、this が2つの場面で使われることを表しています。ひとつはフィールドと引数を区別するとき、もうひとつは別のコンストラクタを呼び出すときです。

この図から分かること

this は単なる書き方の飾りではなく、クラスの内部で処理を整理し、初期化を統一するための重要な役割を持っていることが分かります。特にコンストラクタの連携は、重複したコードを減らすうえでとても有効です。

クラスの定義を学ぶときに混乱しやすいところ

クラスを勉強し始めたときに、つまずきやすい点もいくつかあります。

クラスとオブジェクトの違い

ここは最初に混乱しやすいです。
クラスは設計図、オブジェクトは実体です。

設計図そのものが戦うのではなく、その設計図から作られた戦士が戦います。この感覚がつかめると理解が一気に進みます。

コンストラクタはメソッドっぽいのに違う

コンストラクタは見た目がメソッドに似ていますが、役割が違います。
コンストラクタはオブジェクト生成時の初期化担当で、戻り値も書きません。

this の意味があいまいになる

this は「このオブジェクト自身」です。
引数とフィールドの名前が同じときに使うと、役割が見えやすくなります。

private にしたら使えなくなるのではと思ってしまう

private は「使えなくする」のではなく、「外から直接触らせない」だけです。
必要なら getter や setter のような public メソッドを通して安全に使えるようにします。

クラスの定義を身につけると何ができるようになるか

クラスの定義を理解すると、プログラムをもっと整理された形で書けるようになります。

たとえば、これまではバラバラの変数や処理として書いていたものを、「戦士」「修行メニュー」「アイテム」「試合結果」といったまとまりごとに分けて管理できるようになります。

その結果、次のような良さが出てきます。

良さ内容
見通しがよくなる関連する情報と処理が1か所にまとまる
再利用しやすい同じクラスから何度でもオブジェクトを作れる
修正しやすいクラス単位で整理されているので変更箇所を追いやすい
オブジェクト指向の理解が深まる継承やポリモーフィズムへの土台ができる

クラスの定義は、Javaの学習の中でもとても重要な土台です。
ここが分かると、今後学ぶコンストラクタの応用、継承、カプセル化、インターフェースなどもかなり理解しやすくなります。

おわりに代えて

クラスの定義は、Javaの世界で自分だけの設計図を描けるようになる第一歩です。
フィールドで情報を持たせ、メソッドで動きを与え、コンストラクタで最初の状態を整える。この流れがつかめると、プログラムがただの命令の羅列ではなく、意味のある部品の集まりとして見えてきます。

ドラゴンボール風にいえば、戦士を育てるための道場を自分で設計できるようになる感覚に近いです。どんな力を持ち、どんな技を使い、どんな状態で登場するのかを自分で決められるようになるわけです。

クラス定義は少しずつ慣れていけば大丈夫です。まずは小さなクラスを1つ作ってみて、フィールド、コンストラクタ、メソッドの役割を体感してみるのがおすすめです。そこから先は、Javaの学びがぐっと楽しくなっていきます。