トップ / カリキュラム / 第6章

CHAPTER 06

オブジェクト指向の考え方

Javaの中心にある考え方が「オブジェクト指向」です。難しそうな名前ですが、中身は「書類のひな形と記入済みの書類」「部署の階層」「業務の取り決め」といった、会社で見慣れた整理の仕方そのものです。

読む目安:約25分クラス・継承・インターフェースをたとえ話で

この章でわかること

  1. 「クラス」と「インスタンス(オブジェクト)」の違いを、ひな形と記入済み書類のたとえで説明できる
  2. フィールド(持っている情報)とメソッド(できること)がクラスの中身だとわかる
  3. 「継承」「インターフェース」「カプセル化」という言葉を聞いて、だいたいの意味が浮かぶ

なぜ「オブジェクト指向」が必要になったのか

第5章までの知識で、計算や繰り返しは書けます。しかし業務システムは、数万行、数十万行のコードになります。そうなると「どこに何が書いてあるか」「この変数は誰が変えているのか」が分からなくなり、修正が怖くてできない状態になります。

オブジェクト指向は、この問題への答えとして広まった「コードの整理術」です。考え方の中心はひとつ、「関係するデータと処理を、ひとまとまりの『もの(オブジェクト)』として扱う」ことです。Javaは、この考え方を言語の土台に据えて設計されています。

クラスとインスタンス:ひな形と記入済みの書類

第3章で、クラスは「部品をまとめる箱」だと学びました。オブジェクト指向の視点では、クラスはひな形(設計図)です。そして、そのひな形から作られた個々の実体をインスタンス(またはオブジェクト)と呼びます。

クラス Invoice請求書のひな形
「請求番号・取引先・金額の欄がある」
「税込金額を計算できる」
→
インスタンス①No.1001/A商事/100,000円
インスタンス②No.1002/B物産/80,000円
インスタンス③No.1003/C工業/130,000円
ひな形は1つ、記入済みの書類は何枚でも。クラスは「請求書とはどういうものか」を定義し、インスタンスは「具体的な1枚1枚の請求書」です。第4章で見た String や BigDecimal もクラスで、"請求書" という文字列はStringクラスのインスタンスです。

コードで見るとこうなります。少し長いですが、構造は第3章と同じ「クラスの箱の中にいろいろ入っている」だけです。

public class Invoice {
    // --- フィールド:この「もの」が持っている情報 ---
    private String number;      // 請求番号
    private String customer;    // 取引先
    private int amount;         // 税抜金額

    // --- コンストラクタ:インスタンスを作るときの初期化手順 ---
    public Invoice(String number, String customer, int amount) {
        this.number = number;
        this.customer = customer;
        this.amount = amount;
    }

    // --- メソッド:この「もの」ができること ---
    public int amountWithTax() {
        return amount + amount / 10;   // 10%税込(簡略化)
    }

    public String getCustomer() {
        return customer;
    }
}
  • private String number;フィールド:インスタンスごとに持つデータ。「欄」にあたる。private は「外から直接さわれない」の意味(後述)
  • public Invoice(...) { ... }コンストラクタ:クラス名と同じ名前の特別なメソッド。new で作られるときに1回だけ動き、欄に初期値を入れる
  • this.number = number;「このインスタンスの number 欄に、受け取った number を入れる」。this は「自分自身」
  • public int amountWithTax()メソッド:この請求書ができること。自分の amount を使って計算する

そして、ひな形から実体を作るのが new です。

Invoice inv = new Invoice("1001", "A商事", 100000);   // 記入済み請求書を1枚作る
System.out.println(inv.getCustomer());        // → A商事
System.out.println(inv.amountWithTax());      // → 110000

読んでみる:new Invoice(...) で請求書を1枚作り、inv という変数に入れた。あとは inv.〜() で、その請求書に「取引先を教えて」「税込金額を計算して」と頼んでいる。データ(金額)とそれを使う処理(税込計算)が、同じ箱の中にあるのがポイントです。

第3章の static の意味がここで分かる

static が付いたメソッドやフィールドは、「個々の記入済み書類」ではなく「ひな形そのもの」に属します。main メソッドに static が付いていたのは、「まだ1枚も書類を作っていない起動直後でも、ひな形から直接呼べるようにするため」です。

カプセル化:中身を勝手にさわらせない

先ほどのコードで、フィールドに private が付いていました。これは「このデータはクラスの外から直接書き換えられない」という制限です。外から金額を変えたければ、クラスが用意した公開メソッド(public)を通すしかありません。

これをカプセル化と呼びます。なぜそんな面倒なことをするかというと、「誰でも金額欄を直接書き換えられる」状態だと、どこで値が変わったのか追えなくなるからです。公開メソッドを通すようにしておけば、そこに「マイナスの金額は受け付けない」「承認済みなら変更不可」といったチェックを1か所で入れられます。

内部統制との相性

カプセル化は、業務でいう「勝手に台帳を直させない。必ず決められた手続きを通す」という統制の考え方そのものです。良く設計されたJavaのシステムでは、重要なデータの変更経路が限られているため、「この金額を変えられる処理はどこか」を特定しやすくなっています。監査やシステムレビューで「変更経路が限定されているか」を確認する際の、コード側の裏付けです。

継承:共通部分をまとめて、違いだけ書く

請求書・見積書・納品書は、どれも「番号・取引先・金額」を持ち、「税込金額を計算する」ことができます。違うのは、請求書には支払期限があり、見積書には有効期限がある、といった一部だけです。

こういうとき、共通部分を親クラスにまとめ、それぞれの文書は親を継承(extends)して「違う部分だけ」を書きます。

Document(親クラス)番号・取引先・金額 / 税込金額を計算する
Invoice+ 支払期限
Quotation+ 有効期限
DeliveryNote+ 納品日
継承の利点:税込計算のルールが変わったら、親クラスの1か所を直せば3種類の文書すべてに反映されます。欠点:親を変えると子すべてに影響するため、安易に使うと「どこを直したら何が変わるか分からない」状態を招きます。現代のJava開発では、継承は控えめに使い、次のインターフェースを好む傾向があります。
public class Invoice extends Document {   // Document を継承する
    private String dueDate;                 // 請求書だけが持つ項目
    // 番号・取引先・金額・税込計算は親から引き継ぐので書かなくてよい
}

インターフェース:「できること」の取り決め

インターフェース(interface)は、「このメソッドを持っていること」だけを約束する取り決めです。中身は書かず、「何ができるか」の一覧だけを定めます。

// 取り決め:「印刷できるもの」は print() メソッドを持つこと
public interface Printable {
    void print();
}

// 請求書は「印刷できるもの」の取り決めを守る(implements)
public class Invoice implements Printable {
    public void print() {
        System.out.println("請求書を印刷します");
    }
}

インターフェースがあると、使う側は「相手が請求書か見積書か」を気にせず、「Printable なら print() を呼べる」とだけ考えればよくなります。これは業務でいう「書式は違っても、承認フローに乗せるには申請日と承認者欄が必須」といった共通ルールと同じ発想です。

継承(extends)

「〜の一種である」の関係請求書は文書の一種
中身(データと処理)を引き継ぐ
親は1つだけ

インターフェース(implements)

「〜ができる」の関係請求書は印刷できる・保存できる
「できること」の約束だけを引き継ぐ
いくつでも守れる
エンジニアの会話で「インターフェースを切る」「実装する」と出てきたら、「できることの取り決めを先に決めて、中身は別に作る」という話です。システム間連携の「API」も、広い意味ではこのインターフェースの考え方です。

パッケージとインポート:クラスの整理棚

業務システムには何百、何千というクラスがあります。それをフォルダのように分類するのがパッケージです。第4章で import java.math.BigDecimal; という行がありましたが、あれは「java.math という棚にある BigDecimal クラスを使います」という宣言です。

package com.example.accounting.invoice;   // このクラスの所属(棚の場所)

import java.math.BigDecimal;             // 標準ライブラリから借りる
import java.time.LocalDate;              // 日付クラスも借りる

public class Invoice { ... }

コードの冒頭に import がずらりと並んでいるのはこのためです。何を借りているかを見れば、「このクラスは日付計算と金額計算をしているらしい」と当たりが付きます。

この章のまとめ

  • オブジェクト指向は「関係するデータと処理をひとまとまりとして扱う」整理術。大規模コードを管理するために生まれた
  • クラスはひな形、インスタンス(オブジェクト)は new で作った実体。クラスの中身はフィールド(情報)とメソッド(できること)
  • カプセル化(private)で、データの変更経路を限定する。内部統制の考え方と同じ
  • 継承は「〜の一種」、インターフェースは「〜ができる」の取り決め。現代は継承を控えめに、インターフェースを好む
  • パッケージはクラスの棚。import を見れば何を使っているかの当たりが付く

確認クイズ

この章の内容を3問で確かめましょう。選ぶとすぐに解説が表示されます。

Q1. 「クラス」と「インスタンス」の関係のたとえとして最も適切なものはどれですか?

クラスは「どういうものか」を定めた設計図(ひな形)、インスタンスはそこから new で作られた具体的な実体です。

Q2. フィールドに private を付ける(カプセル化する)主な目的はどれですか?

直接書き換えを禁じ、決められたメソッドを通すことで、チェックを1か所に集め、変更の経路を特定しやすくします。統制の考え方と同じです。

Q3. 「請求書クラスは Printable インターフェースを実装している」とはどういう意味ですか?

インターフェースは「できること」の約束です。中身は引き継がず、「このメソッドを持つ」という取り決めだけを守ります。「〜の一種」は継承(extends)のほうです。

読み終えたら、読了にしておきましょう。トップページのカリキュラムに記録が付きます(このブラウザ内だけに保存されます)。