Java超|getClass()の使い方と役割

見た目は同じサイヤ人戦士名簿に並んでいても、実体のクラスは一人ひとり違います。getClass() を理解すると、オブジェクトが本当にどのクラスから作られたのかを正確に確認できるようになります。

Javaのオブジェクト指向では、スーパークラス型の変数や配列で、サブクラスのオブジェクトを扱うことができます。

たとえば、SaiyanWarrior 型の変数に、SaiyanWarrior オブジェクトだけでなく、SuperSaiyanWarrior オブジェクトを入れることもできます。

SaiyanWarrior warrior1 = new SuperSaiyanWarrior();

このように書くと、変数の型は SaiyanWarrior です。

しかし、実際に作られているオブジェクトは SuperSaiyanWarrior です。

ここで大切になるのが、変数の型と実体のクラスは必ずしも同じではないという点です。

ドラゴンボール風にたとえると、戦士管理本部の名簿では、全員が「サイヤ人戦士」としてまとめられているように見えます。

しかし、実際に一人ずつスカウターで確認してみると、普通のサイヤ人戦士もいれば、スーパーサイヤ人戦士もいます。

名簿上の分類は SaiyanWarrior。
実際の正体は SuperSaiyanWarrior。

このようなことがJavaではよく起こります。

そこで使うのが getClass() です。

getClass() は、オブジェクトが実際にどのクラスから作られたものなのかを調べるメソッドです。

つまり、変数の型を見るのではなく、実体のクラス情報を見るために使います。

見るもの内容
変数の型プログラム上で宣言されている型
実体のクラスnew で実際に作られたオブジェクトのクラス
getClass() で分かるもの実体のクラス情報

getClass() は、Object クラスに用意されているメソッドです。

Javaのすべてのクラスは最終的に Object クラスを継承しているため、SaiyanWarrior や SuperSaiyanWarrior のような自作クラスでも getClass() を使えます。

この記事では、具体的なプログラムとして Sample9.java を例示しながら、getClass() の役割、Object クラスとの関係、Class オブジェクト、スーパークラス型配列に入った実体の確認、ポリモーフィズムとのつながりを、ドラゴンボールの世界観で解説します。

getClass() は何をするメソッドなのか

getClass() は、そのオブジェクトが属しているクラスの情報を返すメソッドです。

言い換えると、オブジェクトの正体となるクラスを調べるためのメソッドです。

基本的な形は次のようになります。

object.getClass()

このように呼び出すと、object が実際にどのクラスから作られたオブジェクトなのかを表す情報が返ってきます。

たとえば、次のコードを考えてみます。

SaiyanWarrior warrior1 = new SuperSaiyanWarrior();

この場合、変数 warrior1 の型は SaiyanWarrior です。

しかし、実際に作られているオブジェクトは SuperSaiyanWarrior です。

見るポイント内容
変数の型SaiyanWarrior
実際のオブジェクトSuperSaiyanWarrior
getClass() で分かるものSuperSaiyanWarrior という実体のクラス情報

このとき、次のように getClass() を呼び出します。

warrior1.getClass()

すると、変数の型である SaiyanWarrior ではなく、実際のオブジェクトである SuperSaiyanWarrior のクラス情報が分かります。

ドラゴンボール風にたとえると、戦士名簿では「サイヤ人戦士」として登録されていても、本人をスカウターで確認すると「この戦士はスーパーサイヤ人クラスです」と分かるようなイメージです。

getClass() は変数の型ではなく実体を見る

getClass() を理解するときに、特に大切なのはここです。

getClass() が見るのは、変数の宣言型ではありません。

実際にその変数が指しているオブジェクトのクラスです。

次のような状態を考えます。

SaiyanWarrior warrior1 = new SuperSaiyanWarrior();

このコードでは、左側と右側で見ているものが違います。

部分意味
SaiyanWarrior warrior1warrior1 は SaiyanWarrior 型の変数
new SuperSaiyanWarrior()実際には SuperSaiyanWarrior オブジェクトを作っている

つまり、変数の型は SaiyanWarrior ですが、実体は SuperSaiyanWarrior です。

この状態で getClass() を使うと、実体のクラスである SuperSaiyanWarrior が分かります。

確認方法分かること
変数の宣言を見るSaiyanWarrior 型として扱っていること
getClass() を使う実体が SuperSaiyanWarrior であること

ドラゴンボール風に言うと、名簿上の分類を見るだけでは、その戦士がどの段階まで覚醒しているかまでは分かりません。

でも、getClass() で確認すれば、実際に立っている戦士が普通のサイヤ人戦士なのか、スーパーサイヤ人戦士なのかを確認できます。

図:getClass() が実体のクラスを調べる流れ

この図が示していること

この図では、SaiyanWarrior 型の変数 warrior1 が、SuperSaiyanWarrior オブジェクトを指している状態を表しています。

左側のカードでは、変数の型が SaiyanWarrior であることを示しています。

右側のカードでは、実際に作られたオブジェクトが SuperSaiyanWarrior であることを示しています。

この状態で warrior1.getClass() を呼び出すと、SaiyanWarrior ではなく、SuperSaiyanWarrior のクラス情報が返されます。

この図から分かることは、getClass() は変数の宣言型ではなく、実際にその変数が指しているオブジェクトのクラスを調べるメソッドだということです。

なぜ getClass() が使えるのか

getClass() は Object クラスのメソッドです。

Javaのすべてのクラスは、最終的に Object クラスにつながっています。

そのため、どんなクラスのオブジェクトでも getClass() を使えます。

これは、toString() や equals() と同じ考え方です。

Object クラスの代表メソッド役割
toString()オブジェクトを文字列で表す
equals(Object obj)オブジェクトが同じかどうか調べる
getClass()オブジェクトのクラス情報を調べる

たとえば、次のようなクラスを作ったとします。

class SaiyanWarrior
{
}

extends Object とは書いていません。

しかし、Javaではスーパークラスを明示しないクラスは、自動的に Object クラスを親に持ちます。

考え方としては、次のような関係です。

class SaiyanWarrior extends Object
{
}

さらに、SuperSaiyanWarrior が SaiyanWarrior を継承している場合、SuperSaiyanWarrior も最終的には Object につながります。

class SuperSaiyanWarrior extends SaiyanWarrior
{
}

この関係を整理すると、次のようになります。

クラスObject とのつながり
SaiyanWarriorObject を継承している
SuperSaiyanWarriorSaiyanWarrior を通じて Object につながる
ScouterObject を継承している
MissionCardObject を継承している

ドラゴンボール風にたとえると、サイヤ人戦士、スーパーサイヤ人戦士、スカウター、任務カードなど、いろいろな種類のオブジェクトがあっても、Java世界の共通の土台である Object から基本機能を受け継いでいます。

その共通機能のひとつが getClass() です。

getClass() が返すのは何か

getClass() が返すのは、単なる文字列ではありません。

getClass() は、Class クラスのオブジェクトを返します。

基本的には、次のように受け取れます。

Class cl = object.getClass();

この cl には、そのオブジェクトのクラス情報が入っています。

メソッド戻り値
getClass()Class クラスのオブジェクト

ここは少し難しく感じるかもしれません。

最初は、Class オブジェクトを「クラス情報が入った情報カード」と考えると分かりやすいです。

Javaの考え方ドラゴンボール風のイメージ
オブジェクト実際に存在する戦士本人
getClass()戦士の正体を確認する動作
Class オブジェクトどのクラスの戦士かを示す身分証カード

たとえば、SuperSaiyanWarrior オブジェクトに getClass() を使うと、「このオブジェクトは SuperSaiyanWarrior クラスです」という情報を持った Class オブジェクトが返されます。

そして、その Class オブジェクトを出力すると、次のように表示されます。

class SuperSaiyanWarrior

つまり、getClass() はクラス名の文字列だけを返しているのではなく、クラス情報を持つ Class オブジェクトを返しているということです。

オブジェクトのクラス情報を調べる

ファイル名:Sample9.java

class SaiyanWarrior
{
    protected String name;
    protected String styleName;

    public SaiyanWarrior()
    {
        name = "戦士未登録";
        styleName = "流派未設定";
        System.out.println("サイヤ人戦士を作成しました。");
    }
}

class SuperSaiyanWarrior extends SaiyanWarrior
{
    private int transformationLevel;

    public SuperSaiyanWarrior()
    {
        transformationLevel = 0;
        System.out.println("スーパーサイヤ人クラスの戦士を作成しました。");
    }
}

class Sample9
{
    public static void main(String[] args)
    {
        SaiyanWarrior[] warriors;
        warriors = new SaiyanWarrior[2];

        warriors[0] = new SaiyanWarrior();
        warriors[1] = new SuperSaiyanWarrior();

        for(int i = 0; i < warriors.length; i++){
            Class cl = warriors[i].getClass();
            System.out.println((i + 1) + "番目のオブジェクトのクラスは"
                               + cl + "です。");
        }
    }
}

実行結果

サイヤ人戦士を作成しました。
サイヤ人戦士を作成しました。
スーパーサイヤ人クラスの戦士を作成しました。
1番目のオブジェクトのクラスはclass SaiyanWarriorです。
2番目のオブジェクトのクラスはclass SuperSaiyanWarriorです。

Sample9.java の中心になる部分

このプログラムで大切なのは、配列の型が SaiyanWarrior[] になっているところです。

SaiyanWarrior[] warriors;
warriors = new SaiyanWarrior[2];

この配列は SaiyanWarrior 型の配列です。

そのため、SaiyanWarrior オブジェクトを入れられます。

warriors[0] = new SaiyanWarrior();

さらに、SuperSaiyanWarrior は SaiyanWarrior を継承しているため、SuperSaiyanWarrior オブジェクトも入れられます。

warriors[1] = new SuperSaiyanWarrior();

整理すると、次のようになります。

配列の位置変数としての型実際に入っているオブジェクト
warriors[0]SaiyanWarriorSaiyanWarrior
warriors[1]SaiyanWarriorSuperSaiyanWarrior

見た目はどちらも SaiyanWarrior 型の配列要素です。

しかし、実体は異なります。

ここで getClass() を使うと、それぞれのオブジェクトの正体を確認できます。

なぜ配列の型ではなく実体のクラスが分かるのか

getClass() は、変数や配列の宣言型を返しているのではありません。

getClass() が見るのは、実際にその変数や配列要素が指しているオブジェクトのクラスです。

そのため、Sample9.java では次のような結果になります。

調べる対象配列としての型実体getClass() の結果
warriors[0]SaiyanWarriorSaiyanWarriorclass SaiyanWarrior
warriors[1]SaiyanWarriorSuperSaiyanWarriorclass SuperSaiyanWarrior

ここが getClass() の重要なところです。

SaiyanWarrior[] 配列に入っているからといって、すべてが SaiyanWarrior の実体だとは限りません。

サブクラスである SuperSaiyanWarrior オブジェクトが入っている場合もあります。

ドラゴンボール風にたとえると、戦士名簿では全員をサイヤ人戦士として並べていても、一人ずつ確認すると「通常のサイヤ人戦士」と「スーパーサイヤ人戦士」が混ざっていることが分かる、ということです。

図:SaiyanWarrior[] 配列の中身を getClass() で確認する

この図が示していること

この図では、SaiyanWarrior[] 配列の中に、SaiyanWarrior オブジェクトと SuperSaiyanWarrior オブジェクトが入っている様子を表しています。

配列の型は SaiyanWarrior[] です。

しかし、warriors[0] の実体は SaiyanWarrior、warriors[1] の実体は SuperSaiyanWarrior です。

getClass() を呼び出すと、配列の型ではなく、実際に入っているオブジェクトのクラス情報が返されます。

呼び出し結果
warriors[0].getClass()class SaiyanWarrior
warriors[1].getClass()class SuperSaiyanWarrior

この図から分かることは、getClass() は「見た目の型」ではなく「実体のクラス」を調べるメソッドだということです。

Class クラスのオブジェクトとは何か

Sample9.java では、getClass() の戻り値を Class 型の変数 cl に入れています。

Class cl = warriors[i].getClass();

この cl には、オブジェクトのクラス情報が入っています。

学習段階では、Class クラスのオブジェクトを、クラス情報を持った身分証カードのように考えると分かりやすいです。

ものドラゴンボール風のイメージ
SaiyanWarrior オブジェクト実際の戦士本人
getClass()戦士の正体を確認する動作
Class オブジェクトどのクラスの戦士かを示す身分証カード

つまり、Class オブジェクトは、クラスそのものについての情報を持っている特別な情報箱です。

たとえば、getClass() の結果を出力すると、次のような表示になります。

class SaiyanWarrior
class SuperSaiyanWarrior

これは、そのオブジェクトがどのクラスに属しているかを示しています。

ここで大切なのは、getClass() の戻り値は String ではなく Class オブジェクトだということです。

表示すると class SaiyanWarrior のように見えますが、内部的にはクラス情報を持つオブジェクトが返っています。

出力結果から分かること

Sample9.java の出力では、次のように表示されています。

1番目のオブジェクトのクラスはclass SaiyanWarriorです。
2番目のオブジェクトのクラスはclass SuperSaiyanWarriorです。

ここから分かるのは、getClass() がきちんとオブジェクトの実体を見ているということです。

順番配列要素実体getClass() の結果
1番目warriors[0]SaiyanWarriorclass SaiyanWarrior
2番目warriors[1]SuperSaiyanWarriorclass SuperSaiyanWarrior

このように、スーパークラス型でまとめて扱っていても、getClass() を使えば、実際のオブジェクトのクラスを確認できます。

ドラゴンボール風に言うと、戦士管理本部の名簿ではどちらも SaiyanWarrior として並んでいます。

しかし、スカウターで実体を確認すると、1番目は SaiyanWarrior、2番目は SuperSaiyanWarrior だと分かります。

getClass() はどんな場面で便利なのか

getClass() は、オブジェクトの種類を確認したいときに便利です。

たとえば、次のような場面があります。

場面getClass() が役立つ理由
配列に複数種類のオブジェクトが入っているどのクラスの実体か確認できる
コレクションに派生クラスが混ざっている中身の正体を調べられる
デバッグ中に型を確認したい変数の型と実体の違いを確認できる
ポリモーフィズムの動きを学びたい実際にどのクラスのオブジェクトか分かる

ドラゴンボール風にたとえると、戦士名簿を見ながら、この札の先にいるのは普通のサイヤ人戦士なのか、スーパーサイヤ人戦士なのかを確認するようなものです。

特に、スーパークラス型の配列やリストに、複数種類のサブクラスが入るようになると、getClass() の役割が分かりやすくなります。

見た目は同じ型で並んでいても、実体はそれぞれ違う。

その違いを調べられるのが getClass() です。

getClass() とポリモーフィズムのつながり

getClass() は、ポリモーフィズムの理解とも深くつながります。

ポリモーフィズムでは、スーパークラス型の変数でサブクラスのオブジェクトを扱えます。

たとえば、次のような状態です。

SaiyanWarrior warrior1 = new SuperSaiyanWarrior();

この場合、次のように整理できます。

見るポイント内容
変数の型SaiyanWarrior
実体SuperSaiyanWarrior

この状態で、show() のようなオーバーライドされたメソッドを呼び出すと、実体である SuperSaiyanWarrior 側のメソッドが動きます。

一方、getClass() を使えば、その実体が何かを確認できます。

メソッド見えるもの
オーバーライドされたメソッド呼び出し実体に応じた処理が動く
getClass()実体のクラス情報が分かる

つまり getClass() は、ポリモーフィズムで見えにくくなりがちなオブジェクトの正体を確認するためのメソッドと考えると分かりやすいです。

ドラゴンボール風にたとえると、戦士管理本部が全員を SaiyanWarrior 型でまとめていても、実際に技を出すと、スーパーサイヤ人戦士はスーパーサイヤ人らしい動きをします。

そして getClass() を使えば、その戦士の実体が SuperSaiyanWarrior であることを確認できます。

Object クラスとのつながりを意識する

getClass() は、toString() や equals() と同じく Object クラスのメソッドです。

そのため、Javaのすべてのクラスで使えます。

Object 由来のメソッド役割
toString()オブジェクトを文字列で表す
equals()オブジェクトが同じかどうかを調べる
getClass()オブジェクトのクラス情報を調べる

Object クラスを理解していると、なぜこれらのメソッドがどのクラスでも使えるのかが自然につながります。

ドラゴンボール風にたとえると、どの戦士や道具も、Java世界の共通の土台である Object から基本機能を受け継いでいます。

そのため、サイヤ人戦士でも、スーパーサイヤ人戦士でも、スカウターでも、任務カードでも、自分のクラス情報を確認する getClass() を使えます。

図:Object クラスから受け継ぐ getClass()

この図が示していること

この図では、getClass() が Object クラスにある基本メソッドであり、SaiyanWarrior や SuperSaiyanWarrior に受け継がれていることを表しています。

Object クラスには、toString()、equals(Object obj)、getClass() のような基本メソッドがあります。

SaiyanWarrior は Object を継承し、SuperSaiyanWarrior は SaiyanWarrior を継承しています。

そのため、SuperSaiyanWarrior も最終的には Object 由来の getClass() を使えます。

また、戦士オブジェクトだけでなく、Scouter や MissionCard のような別の種類のオブジェクトでも getClass() を使えます。

この図から分かることは、getClass() が特定のクラスだけの機能ではなく、Javaのすべてのオブジェクトが使える共通機能だということです。

ドラゴンボール風に getClass() を整理する

getClass() は、ドラゴンボール風にたとえると、戦士オブジェクトに対して、あなたはどの戦士型に属していますかと確認するメソッドです。

見た目は同じ SaiyanWarrior[] 配列に入っていても、実際には次のように違うクラスのオブジェクトが入っている場合があります。

配列上の見た目実体
SaiyanWarrior 型として扱うSaiyanWarrior オブジェクト
SaiyanWarrior 型として扱うSuperSaiyanWarrior オブジェクト

このとき getClass() を使えば、それぞれの実体を確認できます。

実体getClass() の結果
SaiyanWarriorclass SaiyanWarrior
SuperSaiyanWarriorclass SuperSaiyanWarrior

つまり getClass() は、オブジェクトの正体となるクラスを確認するためのメソッドです。

ドラゴンボール風に言えば、戦士名簿では同じサイヤ人戦士として並んでいても、スカウターで本人確認をすると、通常の戦士なのか、スーパーサイヤ人戦士なのかが分かる、ということです。

この内容で押さえておきたいポイント

ポイント内容
getClass()オブジェクトが属しているクラス情報を返すメソッド
定義元Object クラス
すべてのクラスで使える理由Javaのすべてのクラスは Object を継承しているから
戻り値Class クラスのオブジェクト
変数の型との違いgetClass() は変数の宣言型ではなく、実体のクラスを見る
配列での使い方スーパークラス型配列に入った各オブジェクトの正体を確認できる
ポリモーフィズムとの関係スーパークラス型でまとめた中身の実体を確認できる
便利な場面デバッグ、学習、配列やコレクション内の型確認

getClass() を理解すると、スーパークラス型でまとめて扱っているオブジェクトの中身が、実際にはどのクラスなのかを確認できるようになります。

見た目の型と実体のクラスを分けて考える。

この感覚がつかめると、ポリモーフィズムや Object クラスの理解もさらに深まります。