はじめに
自己紹介
皆さん、こんにちは、Udemy講師の斉藤賢哉です。私はこれまで、25年以上に渡って企業システムの開発に携わってきました。特にアーキテクトとして、ミッションクリティカルなシステムの技術設計や、Javaフレームワーク開発などの豊富な経験を有しています。
様々なセミナーでの登壇や雑誌への技術記事寄稿の実績があり、また以下のような書籍も執筆しています。
いずれもJava EE(Jakarta EE)を中心にした企業システム開発のための書籍です。中でも 「アプリケーションアーキテクチャ設計パターン」は、(Javaに限定されない)比較的普遍的なテーマを扱っており、内容的にはまだまだ陳腐化していないため、興味のある方は是非手に取っていただけると幸いです(中級者向け)。
Udemy講座のご紹介
この記事の内容は、私が講師を務めるUdemy講座『Java Basic編』の一部の範囲をカバーしたものです。『Java Basic編』はこちらのリンクから購入できます(セールス対象外のためいつも同じ価格)。また定価の約30%OFFで購入可能なクーポンをQiita内で定期的に発行していますので、興味のある方は、ぜひ私の他の記事をチェックしてみてください。
この講座は、以下のような皆様にお薦めします。
- Javaの言語仕様や文法を正しく理解すると同時に、現場での実践的なスキル習得を目指している方
- 新卒でIT企業に入社、またはIT部門に配属になった、新米システムエンジニアの方
- 長年IT部門で活躍されてきた中堅層の方で、学び直し(リスキル)に挑戦しようとしている方
- 今後、フリーランスエンジニアとしてのキャリアを検討している方
- 「Chat GPT」のエンジニアリングへの活用に興味のある方
- 「Oracle認定Javaプログラマ」の資格取得を目指している方
- IT企業やIT部門の教育研修部門において、新人研修やリスキルのためのオンライン教材をお探しの方
この記事を含むシリーズ全体像
この記事はJava SEの一部の機能・仕様を取り上げたものですが、一連のシリーズになっており、シリーズ全体でJava SEを網羅しています。また認定資格である「Oracle認定Javaプログラマ」(Silver、Gold)の範囲もカバーしています。シリーズの全体像および「Oracle認定Javaプログラマ」の範囲との対応関係については、以下を参照ください。
7.1 クラスの基本
チャプターの概要
このチャプターでは、Javaプログラムの基本的な粒度であるクラスについて、その概念や作成方法、命名規約などについて学びます。
7.1.1 クラスとインスタンスの概念
クラスとは
クラスについてはここまでのレッスンの中でも何度も登場していますが、改めて詳細を説明します。
クラスとは、「顧客」や「商品」のような実在する「モノ」であったり、「取引」や「サービス」のような目に見えない「概念」を、プログラムで表現したものです。クラスは、手続き型言語では分離されていた属性と振る舞いの両者を、一緒に内部に保持します。
例えば「人物」という「モノ」を、クラス(ここではPersonクラス)として表現するケースを考えてみましょう。「人物」には、「名前」「年齢」「性別」といったデータ(属性)と、「挨拶する」といった手続き(振る舞い)があるので、これらを「設計情報」としてPersonクラスの中に定義します。
Javaにおけるクラス
Javaでは、クラスはプログラムの基本的な粒度であり、すべてのコードは必ず何らかのクラスの中に記述します。そしてクラスとクラスを相互に連携させることによって、アプリケーションを構築していきます。
またJavaにおけるクラスは、「第一級オブジェクト」の1つに位置付けられます。「第一級オブジェクト」とは、プログラミング言語において、直接生成したり、変数に代入したり、メソッドの引数や戻り値に指定したりすることができる要素のことです。
Javaにおける「第一級オブジェクト」には、クラスの他、『Java Advanced編』で取り上げるラムダ式(関数)があります。
インスタンスとは
クラスはあくまでも「モノ」の「設計情報」なので、Personクラスの中には、例えばAliceやBobといった、実在する人物の属性は持ちません。それに対してインスタンスとは、「モノ」の「実体」を表す概念です。
Personクラスによって、AliceやBobを表現するためには、Personクラスを基にインスタンスを生成する必要があります。Personクラスのインスタンスは、Personクラスの「設計情報」を基に生成されたもので、AliceやBobといった「実体」の属性と「人物」としての振る舞いが含まれます。生成されたインスタンス同士は、相互に独立した関係になります。
クラスのメンバー
クラスの構成要素をメンバーと呼びます。クラスのメンバーには、フィールド、メソッド、コンストラクタ、初期化子、メンバークラスなどの種類があります。この中でこのチャプターで取り上げるのは、フィールド、メソッド、コンストラクタの3つです。
フィールドとは、クラスが持つ属性(状態)のことであり、メソッドとは、クラスが持つ振る舞いのことです。またコンストラクタとは、インスタンス生成時に呼び出される、特殊なメソッドのようなものです。
7.1.2 クラスとインスタンスの実装
クラスの作成方法
ここではクラスを作成する方法を説明します。
クラスは以下のように宣言します。
class クラス名 {
....フィールド....
....コンストラクタ....
....メソッド....
}
クラスは、classキーワードとその後ろにクラス名を記述することで宣言します。1つのJavaランタイムの中で、同一の名前(厳密にはチャプター9.1で説明するFQCN)を持つ複数のクラスを宣言することはできません。
classキーワードとクラス名の間には、1つ以上のスペースが必要です。クラス名の後ろには{ }
を記述し、クラス全体の範囲を指定します。
クラスには、フィールド、コンストラクタ、メソッドといったメンバーを定義します。
クラスを作成する上で、これらのメンバーをいくつ、どのような位置に記述しても、言語仕様としては問題ありません。ただし可読性確保の観点から、フィールド、コンストラクタ、メソッド、それぞれのメンバーの種類ごとに、記述する位置をまとめた方が望ましいでしょう。一般的には、フィールド、コンストラクタ、メソッドの順に宣言するケースが多く見られます。
それでは先に例として取り上げたPersonクラスを、実際に作成してみましょう。以下のコードを見てください。
class Person {
// フィールド
String name; //【1】名前
int age; //【2】年齢
// コンストラクタ
Person() { //【3】
}
Person(String name, int age) { //【4】
this.name = name;
this.age = age;
}
// メソッド
void sayHello() { //【5】
String message = "こんにちは!私は" + name + "、" + age + "歳です。";
System.out.println(message);
}
}
フィールドが【1】【2】に、コンストラクタが【3】【4】に、メソッドが【5】にそれぞれ相当します。
このコードの内容はチャプター7.2以降で説明しますので、ここではまず「クラスをどのように記述するのか」という点について、概観をつかんでもらえれば問題ありません。
UMLとクラス図
UMLとは、システム設計を視覚化するための標準的なモデリング言語で、システムの構造や振る舞いを標準的な図式によって表現します。UMLには、クラス図、シーケンス図、アクティビティ図、ユースケース図など、14種類のダイアグラムが規定されています。この中でクラス図とは、クラスの属性・振る舞いや、クラスとクラスの関連を表現するために使用します。
本コースではUMLの詳細な説明は割愛しますが、前項のPersonクラスをクラス図で表すと、以下のようになります。
クラスの修飾子
クラスには、その性質を表すために特定の修飾子を付与することがあります。修飾子は、classキーワードの前に記述します。
クラスに付与可能な修飾子には以下の種類がありますが、詳細は別のチャプターで取り上げます。
- public … すべてのクラスからアクセス可能であることを表す(チャプター10.1参照)
- final … 継承を禁止することを表す(チャプター8.2参照)
- abstract … 抽象クラスであることを表す(チャプター11.1参照)
- strictfp … 浮動小数点の演算が実行環境に依存しないことを表す(本コースでは対象外)
クラスの命名
クラス名は一種の識別子のため、「レッスン2.1.5 識別子とキーワード」で触れたルールに則ってさえいれば、任意の名前を付けることができます。ただしクラスの命名には「Upper Camel Case」と呼ばれる記法を採用するのが、一般的なコーディング上の規約です。
「Upper Camel Case」は、単語の先頭や区切り文字を大文字で表すという記法です。例えば「人物」は「Person」、「一般会員」は「GeneralCustomer」という命名になります。また「注文取引」であれば「OrderService」などになるでしょう。
オブジェクト指向開発では、クラスは責務に応じた「名前」を中心に抽出されるため、命名という行為は設計そのものと言えます。詳細は後のチャプターで説明しますが、クラスとクラスは、継承関係になる場合があります。そのとき、例えば顧客というエンティティに対して、CustomerBase、GeneralCustomer、GoldCustomerといった具合に命名すれば、クラス同士が継承関係にある、ということを名前で表現することができます。
繰り返しになりますが、名前によってその責務た分かるようにすることが重要です。例えば単なる「Managerクラス」(何を管理するのかが分からない)や、「Service1_0_3クラス」のように処理コードを付与したもの(設計書を見ないと処理内容が分からない)も、可読性の観点から控えるべきでしょう。また日本語をローマ字化した命名(「Torihikiクラス」など)も、一般的には控えた方が望ましいでしょう。
インスタンス生成
次に、クラスからインスタンスを生成する方法について見ていきます。あるクラスのインスタンス生成は、基本的にはそのクラスの外部(つまり別クラス)で行います。
インスタンスは以下のように生成します。
データ型 変数名 = new クラス名();
new
というのは演算子の一種で、クラスの前に記述することで、そのクラスのインスタンスを生成します。クラス名の後ろには( )
を記述する必要があります。またnew演算子とクラス名の間には1つ以上のスペースが必要です。
このようにnew演算子によって生成されたインスタンスは、参照型変数として取り扱われます。参照型変数については、すでにチャプター3.1で簡単に触れていますが、配列型、クラス型、インタフェース型といった種類があります。ここではクラス型になりますが、その場合のデータ型は基本的にクラス名と同じになります。
以上から既出のPersonクラスからインスタンスを生成するためのコードは、以下のようになります。
Person p = new Person();
この1文にPersonが2回登場しますが、左辺のPersonはデータ型を表し、右辺のPersonはインスタンスを生成する対象クラスを表します。つまりこの命令文は「Personクラスのインスタンスを生成し、それをPerson型変数pに代入する」という意味になります。このようにPersonクラスのインスタンスを生成したら、変数pを起点に、Personクラスが保持するメンバーにアクセスすることが可能になります。
さてこのチャプターはいったんここまでとし、各メンバーの詳細については以降のチャプターで順番に説明します。
本コースでは、開発者が作成したクラスがPersonクラスだとすると、Personクラスから生成されたインスタンスのことを「Personインスタンス」と呼称します。
その一方でインスタンスのことを、オブジェクトと呼ぶことがあります。Java SEのクラスライブラリによって提供されるクラスのインスタンスについては、「Stringオブジェクト」と呼んだ方が"しっくりくる"ため、そのように呼称します。
このようにインスタンスとオブジェクトはニュアンスによって言葉を使い分けることがありますが、基本的に同じ意味だと理解してもらって問題ありません。
このチャプターで学んだこと
このチャプターでは、以下のことを学びました。
- クラスおよびインスタンスの概念や、両者の違いについて。
- クラスのメンバーには、フィールド、メソッド、コンストラクタ、初期化子、メンバークラスなどの種類があること。
- クラスの修飾子にはpublic、finalといった種類があること。
- クラスは「Upper Camel Case」という記法で、責務に応じた命名を行う必要があること。
- Javaでクラスを作成する方法や、インスタンスを生成する方法について。