検索
連載

AIコーディングで理解する、Javaのクラスとオブジェクト指向、インスタンス化、メソッド、コンストラクタAIアシスト時代のJavaプログラミング入門(5)

対話型AI(人工知能)にアドバイスを受けながら進めるJavaプログラミングの入門連載。今回からは、Javaの特徴であるオブジェクト指向的な考え方と、それを実現する構文であるクラスを学習します。まずは基本となるフィールドとメソッド、インスタンス化、コンストラクタを理解しましょう。

Share
Tweet
LINE
Hatena
「AIアシスト時代のJavaプログラミング入門」のインデックス

連載:AIアシスト時代のJavaプログラミング入門

本連載のサンプルコードをGitHubで公開しています。こちらからダウンロードしてみてください。


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

 対話型AI(人工知能)にアドバイスを受けながら進めるJavaプログラミングの入門連載「AIアシスト時代のJavaプログラミング入門」前回までで、Javaの基本(変数、データ型、演算子、制御構文など)を学習してきました。これらは、もちろんJavaの基本ではありますが、どのようなプログラミング言語にも通じるような、いわば基本中の基本という内容でした。

 ここで、第1回を思い出してください。Javaについてまだ何も分からないので、「そもそもJavaとは?」という質問をMicrosoft Copilotに最初の質問として投げてみましたね。そこで得られた回答の一部が図1です。

図1 「そもそもJavaとは?」の回答(再掲)
図1 「そもそもJavaとは?」の回答(再掲)

 Javaの主な特徴の一つに、「オブジェクト指向」であることが挙げられています。しかしながら、これまでの回ではこのオブジェクト指向について、ほとんど触れられてきませんでした。では、Javaにおけるオブジェクト指向の重要度は低いのかというと、とんでもありません。そこで、同じく第1回の質問「以下のJavaプログラムについて説明してくれませんか。」も振り返ってみます(図2)。

図2 「以下のJavaプログラムについて説明してくれませんか。」の回答(再掲、抜粋)
図2 「以下のJavaプログラムについて説明してくれませんか。」の回答(再掲、抜粋)

 「Javaのプログラムはクラス内に記述されます。」とあります。これに対して、

Javaでは、「クラス」を作ることがコーディングの第一歩です。

とも説明しました。そこで「クラスって何?」ということになるわけですが、ここでの重要なキーワードである「オブジェクト指向」と「クラス」の関係について聞いてみると面白そうです。まずはここから始めることにしましょう。

クラスとオブジェクト指向

 クラスとオブジェクト指向の関係を探るために、VS CodeからGitHub Copilot(以降、Copilot)に「オブジェクト指向とクラスの関係について教えて。」と投げてみました。やや長めの回答が得られましたが、これまで通り「まとめ」から見ることにします(図3)。

図3 「オブジェクト指向とクラスの関係について教えて。」の回答(まとめ)
図3 「オブジェクト指向とクラスの関係について教えて。」の回答(まとめ)

 「まとめ」には、以下のように記されています。

  • クラスは「設計図」
  • オブジェクトは「設計図から作られた実体」
  • Javaはこの仕組みを使って、現実世界のものや概念をプログラムで表現します

 3番目に注目です。図1において、「現実社会の問題をより分かりやすくモデル化」と書かれていました。それだけだと少し分かりにくかったのですが、「現実世界のものや概念をプログラムで表現」することがオブジェクト指向であり、そのための方法が「クラス」と「オブジェクト」ということが分かります。さらに、クラスとは「設計図」であり、オブジェクトは「設計図から作られた実体」とあります。

 ここで、図3の上にある回答も見てみましょう(図4)。

図4 「オブジェクト指向とクラスの関係について教えて。」の回答(まとめ以外)
図4 「オブジェクト指向とクラスの関係について教えて。」の回答(まとめ以外)

 図4の(1)は、言い方こそ微妙に異なりますが、オブジェクト指向(OOPと略せるようです)について述べています。(2)が重要で、「設計図」と「実体」の関係、すなわち「クラス」と「オブジェクト」の関係を述べています。改めて(2)を図にしてみました(図5)。

図5 クラスとオブジェクトの関係
図5 クラスとオブジェクトの関係

 こう見ると、まずは設計図であるクラスについて深めてみるとよさそうです。

こんな質問をしてみたい!

 Copilotの回答を読んでみると、クラスやオブジェクトの他に「インスタンス」「インスタンス化」という言葉が出てきます。インスタンスとオブジェクトって何が違うのか、インスタンス化をオブジェクト化と言い換えてもよいのか、そんな疑問が湧きますね。これを聞いてみると、「インスタンス」という日常では使わない言葉の意味がよく分かるかもしれませんよ!

クラス=設計図

 クラスとは設計図であるとして、別の質問を投げてみましょう。図4には、「Javaでの例」として具体的なコードがありました。このコードの「クラス(設計図)」とコメントされている部分を説明してもらいましょう(図6)。

図6 クラスのコードの説明
図6 クラスのコードの説明

 早速「まとめ」を見たいところですが、これは何度も書かれていた内容なので、いきなり説明を見ていきましょう。「このコードの説明」には3つのことが書かれています。これらを踏まえて解説してみましょう。

(1)class Dog { ... }

 Dogという名前のクラス(設計図)の定義です。クラス定義では、classキーワードで始めて、{ ... }の中に定義内容を書いていきます({ ... }は「ブロック」といいます)。定義内容とは、「どんなデータ(フィールド)」と「どんな動き(メソッド)」を持つかをまとめたものとされていますね。

(2)String name;

 「フィールド(メンバ変数)」の宣言です。上の、「どんなデータ(フィールド)」に相当するものですね。ここでは、String型のnameというフィールド(メンバ変数)を宣言していることになります。ちなみにフィールドとは、「場所」や「領域」といった意味です。データの置き場所とイメージすればよいでしょう。

 お気付きでしょうが、第2回で解説した変数の宣言と同じ形式です。形式は同じでも、class定義の中に書くと、そのクラスにあるデータの宣言、という意味になります。この宣言によって、Dogクラスはnameという名前でString型のデータを持つことができます。オブジェクト指向的に表現すると、「Dogクラスのオブジェクトはそれぞれの名前を持つことができる」ということになります。

(3)void bark() { ... }

 「メソッド(動き・振る舞い)」の定義です。上の、「どんな動き(メソッド)」に相当します。ここでは、barkというメソッドを定義していることになります(barkとは「咆える」という意味です)。ところでメソッドとは、「方法」「手段」といった意味です。フィールドが場所だったのに対して、メソッドは動きとなるわけですね。

 これも、どこかで見た形式ですね。第1回で、VS Codeが自動生成したプログラムのコードを図解しましたが、そこに出てきた「mainメソッド」のような形をしています。ただし、それよりははるかにシンプルです。このメソッドについては書き方がフィールドより複雑なので、これは別途解説します。

 barkメソッドは、「Dogオブジェクトが「ワンワン!」と鳴く動作を表しています。」とあるように、動きとしては「鳴く」です。具体的には? というと、{ ... }の中に書かれている内容です。

System.out.println(name + "がワンワン!");

 これも登場済みですね。標準出力に何かを書き出す文です。書き出す内容は「name + "がワンワン!"」となっているように、「nameフィールドに"がワンワン!"をくっつけたもの」を出力します。このように、メソッドではフィールドを使って何かをする、ということが基本的な役割です。

クラスを自動生成する

 では、ここでもう一つ具体的な例を実際のコードとして生成してもらいましょう。今回用に、プロジェクトclass-oopを作成してください。プロジェクトの作り方を忘れてしまった人は、第1回を参照してください。

 今回は、これまで使ってきた[Command]+[I]/[Ctrl]+[I]キーによるチャット形式のコード補完ではなく、コメントからの自動生成を試してみます。そこで、新しいクラスを記述するファイルを新しく作成します。というのは、Javaでは1ファイル=1クラスが基本という約束事があるからです。App.javaファイルにはAppクラスがあるので、新しいクラスのためにファイルを作成するのです。

 ファイルの作成は、VS Codeのファイルエクスプローラーで、「class-oop」の配下にある「src」を右クリックし、メニューから[New Java File]−[Class...]を選択します。コマンドパレットが開くので、「Cat.java」と入力して[Enter]キーを押します。これで、srcフォルダにCat.javaファイルが作成されます。

 Cat.javaファイルを開くと、既にひな型が入力されていますが、これを全て削除してしまい、「// Catクラスの生成」と入力して[Enter]キーを押してください。すると、Catクラスの候補が薄く表示されるので(図7)、問題なければ[Tab]キーを押して確定させます。

図7 「// Catクラスの生成」とコメント入力
図7 「// Catクラスの生成」とコメント入力

 これは、第2回で試した方法(次のコードの提案を次々と受け入れる方法)ですが、このようにコメントからも生成できるので非常に便利です。コメントはコメントで残るので、ちょっとしたメモ書きからもコードを生成できます。例えば、含めたいフィールド、メソッドをあらかじめコメントに入れておけば、それを踏まえたクラス定義を生成してくれます。

図8 Cat.javaの完成
図8 Cat.javaの完成

 自動生成されたCatクラスを見ると、「プロパティ」「コンストラクタ」といった未知の用語が登場しています。この場合、「プロパティ」はフィールドとほぼ同義と思って問題ありません。「コンストラクタ」については、後ほど明らかにしていきます。

こんな質問をしてみたい!

 ここでは、CatクラスのコードはApp.javaの中でなく別途Cat.javaファイルを作成して生成しました。それは、1ファイル=1クラスという約束事があるからですが、なぜそのようにする必要があるのか聞いてみると、Javaがクラスをどのように管理しているかの理解が深まるかもしれませんよ!

オブジェクト=クラスのインスタンス化

 図4では、クラスはあくまでも「設計図」であり、実際に「モノ」として働かせるには「インスタンス化」が必要とありました。これは当たり前のことで、現実社会でも設計図を基に製品を作るなどしないと、具体的に役立てることはできません。これと同じようなことをJavaの世界でも行おうということです。

 具体的なインスタンス化の方法をチャットで聞いてもよいのですが、コード補完をどんどん活用しましょう。App.javaファイルに戻り、既存のSystem.out.…の次の行を入力していきます(System.out.…はコメントアウトしてしまっても構いません)。「// Catクラスのインスタンス化」と入力して[Enter]キーを押します。コードの候補が薄く表示されるので(図9)、[Tab]キーで確定させるのはこれまで通りです。

図9 Catクラスのインスタンス化
図9 Catクラスのインスタンス化

 さて、図4でクラス定義とインスタンス化の関係を図示しましたが、そこに「new」というキーワードがありました。インスタンス化のコードにおいても、「new」があるのを確認できますね。このnewこそ、インスタンス化のためのキーワードです。

クラス名 変数 = new クラス名( ... );

 newによって、クラスがインスタンス化されて、変数に入ります。ちょっと形は違いますが、意味としては第2回でも扱った変数宣言と同じです。インスタンス化により、変数を通じてフィールドやメソッドを使えるということを押さえておきましょう。

こんな質問をしてみたい!

 通常の変数宣言では、newは出てきませんでした。同じく新しく作るのに、片方がnewが必要、もう一方では不要というのも不思議です。なぜそのような決まりになっているか聞いてみると、Javaがどのようにオブジェクトを扱うのかについて理解を深められるかもしれませんよ!

メソッド

 図8でCatクラスを自動生成しましたが、そこにはメソッドmeowの定義がありました。メソッドとは、オブジェクトに「動き」を与えるものです。メソッドmeowの動きとは、「ニャーオと鳴く」です。

メソッドの定義を追加する

 メソッドの定義方法を深掘りするために、もう一つメソッドを追加してみましょう。追加も、コメントによるコード補完で行ってみます。「// 鳴く回数を指定して文字列を返すmeowメソッド」と入力して生成されるコードは図10の通りです(ここからは、確定後のコードを示します)。

図10 追加したmeowメソッド
図10 追加したmeowメソッド

 図10を基に、メソッド定義の構文を図にしてみました(図11)。これを見ると、メソッド定義はメソッドの戻り値、メソッド名、丸カッコの中に引数を並べて、ブロックの中にメソッドの中身を書くことが分かります。

図11 メソッド定義の構文
図11 メソッド定義の構文

【補足】メソッドのオーバーロード

 新しく追加されたメソッドは、最初からあるmeowメソッドに、鳴く回数を引数で指定して、メソッド内で出力するのではなく出力したい文字列を返すようにしたものです。このように、引数の異なる同名のメソッドを定義することができます。これをメソッドの「オーバーロード」といいます。

メソッドを呼び出す

 定義したメソッドは、生成したオブジェクトから呼び出すことができます。App.javaに戻って、メソッドを呼び出すコードを自動生成してもらいましょう。インスタンス化のコードの下に、「// meowメソッドを2つ呼び出す」と入力してコード補完します。まず、1個目のmeowメソッドの呼び出し、次に2個目のmeowメソッドの呼び出し、最後に2個目のmeowメソッドの戻り値の出力と、3行のコードが自動生成されます(図12)。なお、各行の最後にコメントがありますが、これも自動生成されたものです。

図12 meowメソッドを呼び出すコード
図12 meowメソッドを呼び出すコード

 図12を基に、メソッド呼び出しの構文を図にしてみました(図13)。これを見ると、メソッド呼び出しはオブジェクトの変数名、ドット(.)、メソッド名、丸カッコの中にメソッドに渡す引数を並べることが分かります。メソッドが戻り値を返す場合は、それを受け取る変数も宣言しています。

図13 メソッド呼び出しの構文
図13 メソッド呼び出しの構文

【補足】メソッドの引数ヒント

 図13において、メソッド呼び出しの丸カッコの中に「times:」と表示されていますが、これはメソッドの引数ヒントです。渡すべき引数がJavaの拡張機能によって表示されているもので、実際に「times:」と入力するわけではないのに注意しましょう。

 メソッドの定義と呼び出しのコードができたので、実行してみましょう。「Mittens says meow!」が1回だけ表示されている行、3回表示されている行が確認できれば成功です(図14)。

図14 メソッド定義と呼び出しコードの実行結果
図14 メソッド定義と呼び出しコードの実行結果

 ここでは引数のあるmeowメソッドに「3」を渡しているので3回表示されていますが、これをいろいろな数値に変えて、実行結果がどう変わるか確認してみましょう。

こんな質問をしてみたい!

 ここではオーバーロードという仕組みを使って、引数が違うだけの同名のメソッドを定義しました。オーバーロードを使わずに、2番目のメソッドをmeow_some_timesとしてもよさそうなものですが、なぜこのようにするのか聞いてみると、オーバーロードに潜むメリットを知ることができるかもしれませんよ!

コンストラクタ

 最後は、コンストラクタです。図7においては、「// コンストラクタ」とコメントされたコードがありました。ところが、図6で説明させたコードには、この「コンストラクタ」がありませんでした。そこで、チャットにてコンストラクタについて説明させてみましょう。「コンストラクタの役割とは?」と投げてみました(図15)。

図15 「コンストラクタの役割とは?」の回答
図15 「コンストラクタの役割とは?」の回答

 「まとめ」を見るまでもなく、「コンストラクタの役割は、クラスからオブジェクトを生成するときに初期化処理を行うことです。」と明確に示されています。とはいえ、「初期化処理」とは何でしょうか? クラスをインスタンス化する上での初期化処理とは? ということが、その下の「詳しく説明」欄に列挙されています。

  • オブジェクト生成時に自動で呼ばれる特別なメソッドです。
  • フィールド(メンバ変数)に初期値をセットしたり、必要な準備をしたりします。
  • コンストラクタ名はクラス名と同じです。
  • 戻り値(voidなど)は書きません。

 「特別なメソッド」とあるように、メソッドの一種のようです。そしてここが重要で、「フィールド(メンバ変数)に初期値をセットしたり」とあるように、インスタンス化に当たり、フィールドに初期値をセットするのが主要な役割のようです。そして、名前はクラスと同じであるとか、戻り値を表すデータ型は書かないといったルールがあるようです。

 メソッドであるので、コンストラクタ定義の構文はメソッドとほぼ同じと思ってよさそうです。それも踏まえて、コンストラクタの定義構文を図8を基に図にしてみました(図16)。これを見ると、ほとんど図11と同様ですが、戻り値を表すデータ型(voidなど)がないこと、名前がクラス名と同じであることが分かります。

図16 コンストラクタ定義の構文
図16 コンストラクタ定義の構文

【補足】デフォルトコンストラクタ

 ところで、図6ではコンストラクタの定義がなかったのですが、これで大丈夫なのかというと大丈夫です。コンストラクタの定義がない場合、自動的に「デフォルトコンストラクタ」という既定のコンストラクタが生成されます。この場合は、「何もしない」コンストラクタとなりますが、クラスのフィールドは全て自動で初期化されるので、オブジェクトの利用には問題のない状態となっているのです。

コンストラクタを呼び出す

 コンストラクタもメソッドなので、定義したら呼び出すことができます。とはいえ、これは既に行っていて、オブジェクトの生成すなわちクラスのインスタンス化の際に呼び出されています。図9を基に、コンストラクタ呼び出しすなわちインスタンス化の構文を図にしてみました(図17)。newが必要なことは前述の通りですが、引数を与えて呼び出すのがクラス名そのものであること、戻り値がないと言いながら生成したオブジェクトを変数で受け取ることが分かります。

図17 コンストラクタ呼び出しの構文
図17 コンストラクタ呼び出しの構文

複数のインスタンスを生成して利用する

 コンストラクタについて解説したので、引数を変えてコンストラクタを呼び出す、すなわち複数のインスタンスの生成とその利用を試してみましょう。同じくApp.javaにおいて、既存のメソッド呼び出し行の下で、「// もう一つインスタンスを作って同じように使ってみて」と入力して提示コードを確定させましょう(図18)。

図18 もう一つインスタンスを作成してメソッド呼び出し
図18 もう一つインスタンスを作成してメソッド呼び出し

 実行してみましょう。「Mittens 〜」が表示されている行の下に、「Whiskers 〜」が表示されている行を確認できれば成功です(図19)。

図19 もう一つのインスタンスを使用した実行結果
図19 もう一つのインスタンスを使用した実行結果

 このように、異なるインスタンスでは、同じメソッドの呼び出しでも異なる結果となります。インスタンスを複数生成した場合には、それぞれのインスタンスが独立した存在となることを押さえておきましょう。

こんな質問をしてみたい!

 Catクラスのコンストラクタにおいて、「this.name = name;」というような代入文がありました。nameは分かるけどthisって何? ということを聞いてみると、この文の意味するところがより明確になるかもしれませんよ!

まとめ

 今回は、オブジェクト指向的な考え方と、それを実現する構文であるクラスを、フィールド、メソッド、コンストラクタという基本に絞ってCopilotに聞きながら学習しました。

 次回は、オブジェクト指向の三大要素である継承とカプセル化について学習します。

筆者紹介

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


Copyright © ITmedia, Inc. All Rights Reserved.