対話型AI(人工知能)にアドバイスを受けながら進めるJavaプログラミングの入門連載。今回も、オブジェクト指向プログラミングの機能として、列挙型を学習します。特別なクラスとしての列挙型を、その意義とともに理解しましょう。
この記事は会員限定です。会員登録(無料)すると全てご覧いただけます。
本連載のサンプルコードをGitHubで公開しています。こちらからダウンロードしてみてください。
対話型AI(人工知能)にアドバイスを受けながら進めるJavaプログラミングの入門連載「AIアシスト時代のJavaプログラミング入門」。前回は、オブジェクト指向の実用的な機能を知りたいということで、「Javaのオブジェクト指向機能を使った実用的な機能を知りたい。コードは不要です。」という質問を、Visual Studio Code(以降、VS Code)からGitHub Copilot(以降、Copilot)に投げてみました(図1)。
前回は、ここからジェネリクスとコレクションをピックアップして学んだわけですが、まだまだ実用的な機能はありそうです。そこで今回も、オブジェクト指向の延長として、実用的な用途に踏み込んでいきます。今回は8番目の「列挙型(enum)」をピックアップします。なお、モデルには今回も引き続きGPT-5 miniを使っていきます。
列挙型には、「enum」と付記されています。enumのフルスペルはenumerateであり、列挙するという意味ですが、冒頭の図1では、以下のように説明されています。
・定数集合に振る舞いを持たせる。状態管理やモード表現に便利。
「振る舞い」とはメソッドのことと想像できるので、ここでは「定数集合」というのがポイントになりそうです。前回同様に、「列挙型の目的を説明して。初心者でも分かるように専門用語はできるだけ控えて簡潔にコードなしで。」と投げてみました(図2)。
図2には「限られた選択肢を分かりやすくまとめる」とあるので、値というのは定数(値の変化しない変数)で、それをまとめるのが列挙型のようです。また、「曜日・状態・方向など関連する値を1か所で管理できる」というのが、状態管理やモード表現に便利ということのようです。分かりやすいのは曜日ですが、月曜(Monday)、火曜(Tuesday)、日曜(Sunday)などと7個あります。このような限られた選択肢をまとめるのが列挙型だと理解できますね。
以降もそうですが、AIへの質問がくどいと感じられるかもしれません。これは、前回も述べたように、モデルとして採用しているGPT-5 miniの性格によるものです。単純な質問でも網羅性の高い回答やサンプルを提示してくるので、ここではできるだけ基本的な機能について説明してもらうために、ややくどい質問にしています。
このような列挙型の意義を具体的に確かめるために、まずは列挙型を使わずに通常のクラスを用いて、曜日を表す定数の集合を使うコードを示してもらいましょう。前回でも行ったように、「basicプロジェクトを基にenumプロジェクトを作り、列挙型を使わずに曜日を定数で表現したサンプルコードを入れて。」と投げて一連の作業を実行してもらいました(図3)。
enumプロジェクトに、WeekdayConstants.javaとWeekdayApp.javaが作成されます。列挙型を使わないので、これまでの知識+αで読み解けるはずですね。まずはWeekdayConstants.javaに説明を入れてみました(図4)。
重要なのは(2)の7つの定数宣言(定数の集合)です。曜日に相当するMONDAYからSUNDAYに順番に1からの整数値を割り当てています。また、(2)(3)のようにメソッドを定義できます。この例は通常のクラスですから、当たり前ですね。
定数とは、値の変わらない変数を言います。図4で、変数宣言の形式と似ているが、少し違っていることに気付いたでしょう。定数は変数と同じように宣言しますが、finalキーワードを付けます。finalなので、これ以上値が変わらない、最終値というわけです。
このクラスをどのように使うのかを確かめるために、利用側であるWeekdayApp.javaの方も見てみます(図5)。
ここも、重要なのは(1)の変数宣言です。WeekdayConstantsクラスの定数MONDAYでint型変数として初期化しています。これは、WeekdayConstantsクラスにおいて、MONDAYなどがint型の定数として宣言されているからでした。続くメソッド呼び出しについてもここでは触れませんが、同じようにTUESDAYなどを初期値とする整数型変数を宣言して使うというようにイメージしやすいですね。
しかしながら、図3の「注意点(簡潔)」で示されている点に着目すると、この方法は型安全性に問題がありそうです。図4においてWeekdayConstants.MONDAYはint型なので、図5の(4)のようにクラスで定義されていない値(この場合は99)も受け入れてしまいます。とすると、曜日を安全に扱えないということになりますね。
図3には、PowerShellでの実行方法が示されているので、最後に実行結果を見てみましょう(図7)。この実行結果からコードを振り返ってみてください。
図4の(1)では、コンストラクタにprivateが付いていました。これまではコンストラクタにはpublicを付けていたので、意味が違いそうです。「コンストラクタをprivateにする意味は?」と聞いてみると、コンストラクタの役割や呼び出される場面への理解が、より深まるかもしれませんよ。
定数の集合の取り得る値を明確化する仕組みとして、列挙型を使います。図4のコードを、列挙型を使うように修正してもらいましょう。「WeekdayConstants.javaをWeekdayEnum.javaとして列挙型を使うようにできるだけシンプルに置き換えて。WeekdayApp.javaにも利用コードを追加して。元のコードを残すこと。」と投げてみました(図8)。「元のコードを残すこと。」と加えたのは、既存のコード(図5のコード)を消去してしまうことがあるからです。
enumプロジェクトに、WeekdayEnum.javaが追加され、WeekdayApp.javaが更新されます。WeekdayEnum.javaは図10のような内容で、メソッド定義部分を除くと非常にシンプルです。これらのコードについて説明してもらいましょう。「生成されたWeekdayEnum.javaのコードを、専門用語を使って要点のみ説明して。コードの説明以外は不要です。」と投げてみました(図9)。
だいぶ簡潔な説明ですが、これを基に対応するコードに簡単な説明を入れてみました(図10)。
(1)のように、列挙型はclassキーワードではなくenumキーワードで定義します。列挙定数として、(2)のように各曜日に相当するMONDAY、TUESDAY、WEDNESDAYなどを記述していくのが、クラスとの大きな違いです。各列挙定数には、大文字で名前を付けていくのが基本です。WeekdayConstantsクラスでは整数型定数を定義していましたが、列挙型では列挙定数として名前だけ指定すれば済みます。
列挙型には、(3)のように振る舞い(メソッド)を持たせることができます。(4)のように==演算子で同一性の比較ができる他、(5)のように列挙型に用意されるメソッド(ここれはname)を利用することができます。
AIの回答では特に触れられていませんでしたが、全ての列挙型はjava.lang.Enumクラスを継承します。クラスの継承のようなextendsキーワードは不要で、暗黙のうちに継承されます。java.lang.Enumクラスは(5)のnameメソッドをはじめとして表1に挙げるメソッドを実装しており、全ての列挙型で利用できます。
| メソッド | 概要 |
|---|---|
| name() | 列挙定数の名前に相当する文字列を返す(MONDAY→"MONDAY") |
| values() | 列挙定数のリストを返す(拡張for文などで利用できる) |
| ordinal() | 列挙定数の内部値(0からの整数)を返す |
| valueOf() | 文字列から列挙定数を返す("MONDAY"→MONDAY) |
| 表1 java.lang.Enumクラスのメソッド | |
列挙型を利用する、WeekdayApp.javaも見てみます(図11)。
列挙型のインスタンスは(1)のようにnewを使わずに「WeekdayEnum.MONDAY」のように「列挙型.値」の形式で宣言します。後は、変数によって列挙型の値(MONDAYなど)を直接参照したり、メソッドを呼び出すことができます。
定数版ではint型の変数であったのに対して、ここではWeekdayEnum型となっている点にも注目です。変数eTodayにはWeekdayEnumクラスのインスタンス以外は入らないということになり、これが型安全性につながるということですね。もし、MONDAYとかでなく99といった値を直接入れようとしたら、コンパイル時点でエラーとしてくれるわけです。
(2)のように列挙型インスタンスを表示しようとすると、オーバーライドされたtoStringメソッドによって識別子文字列が取得されます。(4)と(5)では、列挙体に備わっているvaluesメソッドとordinalメソッドを使っています。
前節と同様に、最後に実行結果を見てみましょう(図13)。
図2には、「処理の分岐や表示が簡単になる」とも示されていました。提示されたコードにはそれに相当するものがありませんでしたが、このコードを追加してもらうと、列挙型の用途への理解がさらに深まるかもしれませんよ!
ここまでで、列挙型のごくごく基本的なところを理解できたと思います。取り得る値(列挙定数)の一覧を持ち、メソッドも定義できるということですね。しかしながら、列挙型の機能はこれだけではないはずです。そこで、「WeekdayEnum.javaをWeekdayEnumAdvance.javaとして列挙型の進んだ機能を使うように置き換えて。WeekdayApp.javaにも利用コードを追加して。元のコードを残すこと。」と投げてみました(図14)。
enumプロジェクトに、WeekdayEnumAdvance.javaが追加され、WeekdayApp.javaが更新されます。WeekdayEnumAdvance.javaはかなり長く、一見何をしているのか分からないので、これらのコードについて説明してもらいましょう。「生成されたWeekdayEnumAdvance.javaのコードを、専門用語を使って要点のみ説明して。コードの説明以外は不要です。」と投げてみました(図15)。
これもかなり簡潔な説明ですが、これを基に対応するコードに簡単な説明を入れてみました(図16)。
以下、図16の赤字を補足する形で、図15の回答も使いながらコードを説明します。
・不変フィールドを持ち、コンストラクタで初期化する
(3)のように、列挙型はクラスと同様にフィールドを持つことができます。フィールドは自由に定義でき、ここではnumber(1からの整数)、shortName(短縮名)、weekend(週末フラグ)の3つが定義されています。finalが指定されているように、初期化されたら不変のフィールドとなっています。
フィールドは(5)のコンストラクタで初期化されます。コンストラクタは(2)のように列挙定数ごとに呼び出されます。つまり列挙定数は、それぞれがWeekdayEnumAdvance型のインスタンスということです。列挙型では、インスタンス化は自動で行われ、通常のクラスのようにnewを使って明示的に行う必要はありません。
定数のようにfinalキーワードを付けてフィールドを宣言すると、それは不変フィールドになります。初期化したら以降は値が変わりません(不変)。定数と異なり、staticが付いていないことに注意しましょう。
・メソッドの定義
WeekdayEnumAdvance型では、(6)にある上記の不変フィールドに対するゲッターメソッド(getNumber、getShortName、isWeekend)の他、next、previous、fromNumberというユーティリティーメソッドも(7)のように定義しています。ユーティリティーメソッドでは、列挙型で使えるvaluesメソッド、ordinalメソッドも使われています。
(8)のtoStringメソッドの実装は、WeekdayEnum型とは変わっていて、「識別子文字列(短縮形)」と整形して文字列化しています。この当たりは、継承とオーバーライドの仕組みで理解できますね。
WeekdayEnumAdvance型を利用する、WeekdayApp.javaの該当箇所も見てみます(図17)。
ほとんど、これまでの説明で読み解けると思います。ただし1カ所だけ、新しい内容があります。(4)のEnumSetを使った例です。EnumSetとは、前回に説明したコレクション、特にセットの一種です。列挙型に特化されており、列挙型のインスタンスを受け入れ、要素の存在を確認するcontainsメソッドなどを利用できます。
これまでと同様に、最後に実行結果を見てみましょう(図19)。
図16の(4)については、特に説明をしていませんでした。この部分は、(7)のfromNumberメソッドで使うHashMapを作成していますが、staticで始まるブロックなど、見慣れない形式をしています。staticは他の場所にも登場するので、クラスや列挙型でstaticを使う意味を聞いてみると、クラスとインスタンスの関係への理解が、より進むかもしれませんよ。
今回は、特別なクラスとしての列挙型をAIに聞きながら学習しました。
次回は、不変オブジェクトとレコード型を学習します。
WINGSプロジェクト 山内直
WINGSプロジェクト所属のテクニカルライター。出版社秀和システムを経てフリーランスとして独立。ライター、編集者、開発者、講師業に従事。屋号は「たまデジ。」。
・たまデジ。 | たまプラーザで生活、仕事する。(https://naosan.jp/)
WINGSプロジェクト
有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティー(代表山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手掛ける。2021年10月時点での登録メンバーは55人で、現在も執筆メンバーを募集中。興味のある方は、どしどし応募頂きたい。著書、記事多数。
・サーバーサイド技術の学び舎 - WINGS(https://wings.msn.to/)
・RSS(https://wings.msn.to/contents/rss.php)
・X: @WingsPro_info(https://x.com/WingsPro_info)
・Facebook(https://www.facebook.com/WINGSProject)
プログラマー以外にもおすすめ 「Visual Studio Code」のインストールから基本設定まで
Visual Studio Codeを活用するための人気TIPS 12選
初心者向け、データ分析・AI・機械学習の勉強方法 Deep Insiderで学ぼうCopyright © ITmedia, Inc. All Rights Reserved.