1. 概要

Javaでは、クラスjava.lang.Classは、すべてのリフレクション操作のエントリポイントです。 java.lang.Class のオブジェクトを取得したら、対応するメソッドを呼び出して、リフレクションクラスのオブジェクトを取得できます。

このチュートリアルでは、 java.lang.Classのオブジェクトを取得する2つの異なる方法の違いについて説明します。

  • Object.getClass()メソッドの呼び出し
  • .class構文の使用

2. 2つのアプローチの簡単な紹介

Object.getClass()メソッドは、Objectクラスのインスタンスメソッドです。 オブジェクトがある場合は、 object.getClass()を呼び出して、そのタイプのClassオブジェクトを取得できます。

同様に、 ClassName.class 構文を使用して、そのタイプのClassオブジェクトを取得できます。 例はそれを明確に説明することができます:

@Test
public void givenObjectAndType_whenGettingClassObject_thenTwoMethodsHaveTheSameResult() {
    String str = "I am an object of the String class";

    Class fromStrObject = str.getClass();
    Class clazz = String.class;

    assertSame(fromStrObject, clazz);
}

上記のテストメソッドでは、前述の2つの方法を使用して、StringクラスのClassオブジェクトを取得しようとします。 最後に、アサーションメソッドは、2つのClassオブジェクトが同じインスタンスであることを示しています。

ただし、2つのアプローチには違いがあります。 それらを詳しく見てみましょう。

3. ランタイムタイプと 静的タイプ

前の例を簡単に確認しましょう。 str.getClass()メソッドを呼び出すと、strオブジェクトのランタイムタイプを取得します。 一方、String.classはStringクラスを静的に評価します 。 この例では、strString.classのランタイムタイプは同じです。

ただし、クラスの継承がパーティに参加する場合は、異なる可能性があります。 2つの簡単なクラスを見てみましょう。

public class Animal {
    protected int numberOfEyes;
}

public class Monkey extends Animal {
    // monkey stuff
}

次に、 Animal クラスのオブジェクトをインスタンス化して、別のテストを実行しましょう。

@Test
public void givenClassInheritance_whenGettingRuntimeTypeAndStaticType_thenGetDifferentResult() {
    Animal animal = new Monkey();

    Class runtimeType = animal.getClass();
    Class staticType = Animal.class;

    assertSame(staticType, runtimeType);
}

上記のテストを実行すると、テストが失敗します。

java.lang.AssertionError: ....
Expected :class com.baeldung.getclassobject.Animal
Actual   :class com.baeldung.getclassobject.Monkey

テスト方法では、インスタンス化しても動物オブジェクトによって動物動物=newMonkey(); それ以外の猿の動物=新しい猿(); 、のランタイムタイプ動物オブジェクトはまだです猿。 これは、 動物オブジェクトはのインスタンスです実行時。

ただし、 Animal クラスの静的型を取得すると、型は常にAnimalになります。

4. プリミティブタイプの処理

Javaコードを作成するときは、プリミティブ型を頻繁に使用します。 object.getClass()アプローチを使用して、プリミティブ型のClassオブジェクトを取得してみましょう。

int number = 7;
Class numberClass = number.getClass();

上記のコードをコンパイルしようとすると、コンパイルエラーが発生します。

Error: java: int cannot be dereferenced

number 変数はプリミティブ変数であるため、コンパイラーはそれを逆参照できません。 したがって、 object.getClass()メソッドは、プリミティブ型のClassオブジェクトを取得するのに役立ちません。

.class構文を使用してプリミティブ型を取得できるかどうかを見てみましょう。

@Test
public void givenPrimitiveType_whenGettingClassObject_thenOnlyStaticTypeWorks() {
    Class intType = int.class;
    assertNotNull(intType);
    assertEquals("int", intType.getName());
    assertTrue(intType.isPrimitive());
}

したがって、int.classを介してintプリミティブ型のClassオブジェクトを取得できます。  Javaバージョン9以降では、プリミティブ型のClassオブジェクトはjava.baseモジュールに属します。

テストが示すように、 .class構文は、プリミティブ型のClassオブジェクトを取得する簡単な方法です。

5. インスタンスなしでクラスを取得する

object.getClass()メソッドは、そのランタイムタイプのClassオブジェクトを提供できることを学びました。

ここで、ある型の Class オブジェクトを取得したいが、 abstract クラスであるため、ターゲット型のインスタンスを取得できない場合を考えてみましょう。 X180X]インターフェイス、、または一部のクラスではインスタンス化が許可されていません。

public abstract class SomeAbstractClass {
    // ...
}

interface SomeInterface {
   // some methods ...
}

public class SomeUtils {
    private SomeUtils() {
        throw new RuntimeException("This Util class is not allowed to be instantiated!");
    }
    // some public static methods...
}

このような場合、 object.getClass()メソッドを使用してこれらのタイプの Class オブジェクトを取得することはできませんが、.class構文を使用して取得することはできます。それらのクラスオブジェクト

@Test
public void givenTypeCannotInstantiate_whenGetTypeStatically_thenGetTypesSuccefully() {
    Class interfaceType = SomeInterface.class;
    Class abstractClassType = SomeAbstractClass.class;
    Class utilClassType = SomeUtils.class;

    assertNotNull(interfaceType);
    assertTrue(interfaceType.isInterface());
    assertEquals("SomeInterface", interfaceType.getSimpleName());

    assertNotNull(abstractClassType);
    assertEquals("SomeAbstractClass", abstractClassType.getSimpleName());

    assertNotNull(utilClassType);
    assertEquals("SomeUtils", utilClassType.getSimpleName());
}

上記のテストが示すように、 .class 構文は、これらのタイプのClassオブジェクトを取得できます。

したがって、 Classオブジェクトが必要であるが、その型のインスタンスを取得できない場合は、.class構文が最適です。

6. 結論

この記事では、あるタイプの Classオブジェクトを取得する2つの異なる方法を学びました。object.getClass()メソッドと.class構文です。

後で、2つのアプローチの違いについて説明しました。 次の表は、明確な概要を示しています。

object.getClass() SomeClass.class
クラスオブジェクト オブジェクトのランタイムタイプ SomeClassの静的タイプ
プリミティブタイプ 簡単に動作します
インターフェイス、抽象クラス、またはインスタンス化できないクラス 簡単に動作します

 

いつものように、記事の完全なソースコードは、GitHubから入手できます。