1概要

この記事では、クラス、インターフェース、フィールド、およびメソッドの実行時属性を検査または変更することを可能にするJavaリフレクションを検討します。これは、コンパイル時に名前がわからないときに特に便利です。

さらに、リフレクションを使用して、新しいオブジェクトをインスタンス化し、メソッドを呼び出し、フィールド値を取得または設定できます。


2プロジェクト設定

  • Javaリフレクションを使用するために、特別なjar、特別な設定、Mavenの依存関係を含める必要はありません。 JDKにはhttps://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html[

    java.lang.reflect

    ]パッケージにバンドルされたクラスのグループが付属しています特にこの目的のために。

だから私たちがする必要があるのは私たちのコードに次のインポートをすることです。

import java.lang.reflect.** ;

そして私達は行ってもいいです。

インスタンスのクラス、メソッド、およびフィールド情報にアクセスするには、オブジェクトの実行時クラス表現を返す

getClass

メソッドを呼び出します。返された

class

オブジェクトは、クラスに関する情報にアクセスするためのメソッドを提供します。


3簡単な例

足を濡らすために、実行時に単純なJavaオブジェクトのフィールドを検査する非常に基本的な例を見ていきます。


name

フィールドと

age

フィールドのみを持ち、メソッドをまったく持たない単純な

Person

クラスを作成しましょう。これがPersonクラスです。

public class Person {
    private String name;
    private int age;
}

このクラスのすべてのフィールドの名前を見つけるために、今度はJavaリフレクションを使用します。リフレクションの力を理解するために、

Person

オブジェクトを作成し、Objectを参照型として使用します。

@Test
public void givenObject__whenGetsFieldNamesAtRuntime__thenCorrect() {
    Object person = new Person();
    Field[]fields = person.getClass().getDeclaredFields();

    List<String> actualFieldNames = getFieldNames(fields);

    assertTrue(Arrays.asList("name", "age")
      .containsAll(actualFieldNames));
}

このテストは、オブジェクトへの参照がそのオブジェクトの親型であっても、

person

オブジェクトから

Field

オブジェクトの配列を取得できることを示しています。

上記の例では、私たちはそれらのフィールドの名前だけに興味を持っていました、しかしすることができるはるかに多くがあります、そして、私たちは後続のセクションでこれのさらなる例を見るでしょう。

実際のフィールド名を抽出するためにどのようにヘルパーメソッドを使用するかに注目してください。これは非常に基本的なコードです。

private static List<String> getFieldNames(Field[]fields) {
    List<String> fieldNames = new ArrayList<>();
    for (Field field : fields)
      fieldNames.add(field.getName());
    return fieldNames;
}


4 Javaリフレクションのユースケース

Javaリフレクションのさまざまな機能に進む前に、それを見つけるための一般的な用途について説明します。 Javaリフレクションは非常に強力で、さまざまな点で非常に便利です。

たとえば、多くの場合、データベーステーブルには命名規則があります。生徒データを含むテーブルが

tbl

student

data

となるように、テーブル名を

tbl

__で事前に固定することで一貫性を追加することを選択できます。

そのような場合は、生徒データを保持するJavaオブジェクトに

Student

または

StudentData.という名前を付けます。次に、CRUDパラダイムを使用して、

Create

操作が

Object__パラメーターのみを受け取るように、各操作ごとに1つのエントリポイントを持ちます。

その後、リフレクションを使用してオブジェクト名とフィールド名を取得します。この時点で、このデータをDBテーブルにマップし、オブジェクトフィールドの値を適切なDBフィールド名に割り当てることができます。


5 Javaクラスの検査

このセクションでは、JavaリフレクションAPIの最も基本的なコンポーネントを探ります。前述したように、Javaクラスオブジェクトは、任意のオブジェクトの内部詳細へのアクセスを可能にします。

オブジェクトのクラス名、それらの修飾子、フィールド、メソッド、実装されたインターフェースなどの内部の詳細を調べます。


5.1. 準備をする

リフレクションAPIをしっかりと把握するために、Javaクラスに適用され、さまざまな例があるように、

Eating

インターフェースを実装する抽象

Animal

クラスを作成します。このインタフェースは、作成した具体的な

Animal

オブジェクトの摂食動作を定義します。

だから最初に、これは

Eating

インターフェースです:

public interface Eating {
    String eats();
}

それから

Eating

インターフェースの具体的な

Animal

実装:

public abstract class Animal implements Eating {

    public static String CATEGORY = "domestic";
    private String name;

    protected abstract String getSound();

   //constructor, standard getters and setters omitted
}

動物の動きを記述する

Locomotion

という別のインターフェイスも作成しましょう。

public interface Locomotion {
    String getLocomotion();
}


Animal

を拡張して

Locomotion

を実装する

Goat

という具象クラスを作成します。スーパークラスは

Eating

を実装しているので、

Goat

はそのインターフェースのメソッドも実装する必要があります。

public class Goat extends Animal implements Locomotion {

    @Override
    protected String getSound() {
        return "bleat";
    }

    @Override
    public String getLocomotion() {
        return "walks";
    }

    @Override
    public String eats() {
        return "grass";
    }

   //constructor omitted
}

これ以降は、上記のクラスとインタフェースに現れるJavaオブジェクトの側面を調べるために、Javaリフレクションを使用します。


5.2. クラス名


Class

からオブジェクトの名前を取得することから始めましょう。

@Test
public void givenObject__whenGetsClassName__thenCorrect() {
    Object goat = new Goat("goat");
    Class<?> clazz = goat.getClass();

    assertEquals("Goat", clazz.getSimpleName());
    assertEquals("com.baeldung.reflection.Goat", clazz.getName());
    assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName());
}


Class



getSimpleName

メソッドは、宣言に表示されるとおりにオブジェクトの基本名を返します。その後、他の2つのメソッドは、パッケージ宣言を含む完全修飾クラス名を返します。

完全修飾クラス名しかわからない場合は、

Goat

クラスのオブジェクトを作成する方法も見てみましょう。

@Test
public void givenClassName__whenCreatesObject__thenCorrect(){
    Class<?> clazz = Class.forName("com.baeldung.reflection.Goat");

    assertEquals("Goat", clazz.getSimpleName());
    assertEquals("com.baeldung.reflection.Goat", clazz.getName());
    assertEquals("com.baeldung.reflection.Goat", clazz.getCanonicalName());
}

静的な

forName

メソッドに渡す名前にはパッケージ情報を含める必要があります。それ以外の場合は

ClassNotFoundException

が返されます。


5.3. クラス修飾子


Integerを返す

getModifiers__メソッドを呼び出すことで、クラスで使用されている修飾子を決定できます。各修飾子は、設定またはクリアされるフラグビットです。



java.lang.reflect.Modifier


クラスは、返された

Integer

のプレゼンスを分析する静的メソッドを提供します。特定の修飾子がない。

上記で定義したクラスのいくつかの修飾子を確認しましょう。

@Test
public void givenClass__whenRecognisesModifiers__thenCorrect() {
    Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");
    Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");

    int goatMods = goatClass.getModifiers();
    int animalMods = animalClass.getModifiers();

    assertTrue(Modifier.isPublic(goatMods));
    assertTrue(Modifier.isAbstract(animalMods));
    assertTrue(Modifier.isPublic(animalMods));
}

プロジェクトにインポートしているライブラリjar内にあるクラスの修飾子を調べることができます。

ほとんどの場合、本格的なインスタンス化ではなく

forName

アプローチを使用する必要があるかもしれません。それは、メモリが重いクラスの場合には高価なプロセスになるからです。


5.4. パッケージ情報

Javaリフレクションを使用することで、クラスやオブジェクトのパッケージに関する情報を取得することもできます。このデータは、クラスオブジェクトの

getPackage

メソッドの呼び出しによって返されるhttps://docs.oracle.com/javase/8/docs/api/java/lang/Package.html[

Package

]クラス内にバンドルされています。

テストを実行してパッケージ名を取得しましょう。

@Test
public void givenClass__whenGetsPackageInfo__thenCorrect() {
    Goat goat = new Goat("goat");
    Class<?> goatClass = goat.getClass();
    Package pkg = goatClass.getPackage();

    assertEquals("com.baeldung.reflection", pkg.getName());
}


5.5. スーパークラス

Javaリフレクションを使用して、任意のJavaクラスのスーパークラスを取得することもできます。

多くの場合、特にライブラリクラスやjavaの組み込みクラスを使用している間は、使用しているオブジェクトのスーパークラスが事前にわからないことがあります。このサブセクションでは、この情報を取得する方法を説明します。

それでは、先に進み、

Goatのスーパークラスを決定します。さらに、

java.lang.String

classが

java.lang.Object__ classのサブクラスであることも示します。

@Test
public void givenClass__whenGetsSuperClass__thenCorrect() {
    Goat goat = new Goat("goat");
    String str = "any string";

    Class<?> goatClass = goat.getClass();
    Class<?> goatSuperClass = goatClass.getSuperclass();

    assertEquals("Animal", goatSuperClass.getSimpleName());
    assertEquals("Object", str.getClass().getSuperclass().getSimpleName());
}


5.6. 実装されているインタフェース

Javaリフレクションを使用して、特定のクラスによって実装されたインタフェースのリストを取得することもできます。


Goat

クラスと

Animal

抽象クラスによって実装されたインタフェースのクラス型を取得しましょう。

@Test
public void givenClass__whenGetsImplementedInterfaces__thenCorrect(){
    Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");
    Class<?> animalClass = Class.forName("com.baeldung.reflection.Animal");

    Class<?>[]goatInterfaces = goatClass.getInterfaces();
    Class<?>[]animalInterfaces = animalClass.getInterfaces();

    assertEquals(1, goatInterfaces.length);
    assertEquals(1, animalInterfaces.length);
    assertEquals("Locomotion", goatInterfaces[0].getSimpleName());
    assertEquals("Eating", animalInterfaces[0].getSimpleName());
}

各クラスは単一のインタフェースのみを実装していることがアサーションからわかります。これらのインタフェースの名前を調べると、

Goat



Locomotion

を実装し、

Animal



Eating

を実装しています。


Goat

は抽象クラス

Animal

のサブクラスであり、インタフェースメソッド

eats()

を実装していることに気付いたかもしれません。そして、

Goat



Eating

インタフェースを実装しています。

したがって、

implements

キーワードを使用して実装されているとクラスが明示的に宣言しているインタフェースだけが、返される配列に表示されることに注意する価値があります。

つまり、スーパークラスがそのインターフェイスを実装するためにクラスがインターフェイスメソッドを実装していても、サブクラスがそのインターフェイスを

implements

キーワードで直接宣言しない場合、そのインターフェイスはインターフェイスの配列に表示されません。


5.7. コンストラクタ、メソッド、およびフィールド

Javaリフレクションを使用すると、オブジェクトのクラスやメソッドやフィールドのコンストラクタを調べることができます。

後でクラスのこれらの各コンポーネントの詳細な検査を見ることができるようになるでしょうが、現時点では、単にそれらの名前を取得し、それらを期待するものと比較するだけで十分です。


Goat

クラスのコンストラクタを取得する方法を見てみましょう。

@Test
public void givenClass__whenGetsConstructor__thenCorrect(){
    Class<?> goatClass = Class.forName("com.baeldung.reflection.Goat");

    Constructor<?>[]constructors = goatClass.getConstructors();

    assertEquals(1, constructors.length);
    assertEquals("com.baeldung.reflection.Goat", constructors[0].getName());
}

以下のように

Animal

クラスのフィールドを調べることもできます。

@Test
public void givenClass__whenGetsFields__thenCorrect(){
    Class<?> animalClass = Class.forName("com.baeldung.java.reflection.Animal");
    Field[]fields = animalClass.getDeclaredFields();

    List<String> actualFields = getFieldNames(fields);

    assertEquals(2, actualFields.size());
    assertTrue(actualFields.containsAll(Arrays.asList("name", "CATEGORY")));
}


Animal

クラスのメソッドを調べることができるのと同じように、

@Test
public void givenClass__whenGetsMethods__thenCorrect(){
    Class<?> animalClass = Class.forName("com.baeldung.java.reflection.Animal");
    Method[]methods = animalClass.getDeclaredMethods();
    List<String> actualMethods = getMethodNames(methods);

    assertEquals(4, actualMethods.size());
    assertTrue(actualMethods.containsAll(Arrays.asList("getName",
      "setName", "getSound")));
}


getFieldNames

と同様に、

Method

オブジェクトの配列からメソッド名を取得するためのヘルパーメソッドを追加しました。

private static List<String> getMethodNames(Method[]methods) {
    List<String> methodNames = new ArrayList<>();
    for (Method method : methods)
      methodNames.add(method.getName());
    return methodNames;
}


6. コンストラクタの検査

Javaリフレクションを使用すると、任意のクラスのコンストラクタを検査し、さらに実行時にクラスオブジェクトを作成することもできます。これはhttps://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Constructor.html[

java.lang.reflect.Constructor

]クラスによって可能になります。

先ほど、

__constructor

__オブジェクトの配列を取得する方法のみを調べました。そこからコンストラクタの名前を取得できました。

このセクションでは、特定のコンストラクタを取得する方法に焦点を当てます。

Javaでは、私たちが知っているように、クラスの2つのコンストラクタがまったく同じメソッドシグネチャを共有することはありません。そのため、この一意性を利用して多数のコンストラクタから1つのコンストラクタを取得します。

このクラスの機能を理解するために、3つのコンストラクタを持つ

Animal



Bird

サブクラスを作成します。さらに多様性を追加するために、コンストラクタ引数を使用してその動作を指定できるように、

Locomotion

を実装しません。

public class Bird extends Animal {
    private boolean walks;

    public Bird() {
        super("bird");
    }

    public Bird(String name, boolean walks) {
        super(name);
        setWalks(walks);
    }

    public Bird(String name) {
        super(name);
    }

    public boolean walks() {
        return walks;
    }

   //standard setters and overridden methods
}

このクラスには3つのコンストラクタがあることを熟考して確認しましょう。

@Test
public void givenClass__whenGetsAllConstructors__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Constructor<?>[]constructors = birdClass.getConstructors();

    assertEquals(3, constructors.length);
}

次に、コンストラクタのパラメータクラス型を宣言された順序で渡すことによって、

Bird

クラスの各コンストラクタを取得します。

@Test
public void givenClass__whenGetsEachConstructorByParamTypes__thenCorrect(){
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");

    Constructor<?> cons1 = birdClass.getConstructor();
    Constructor<?> cons2 = birdClass.getConstructor(String.class);
    Constructor<?> cons3 = birdClass.getConstructor(String.class, boolean.class);
}

指定された順序で指定されたパラメータ型を持つコンストラクタが存在しない場合、

NoSuchMethodException

が発生し、テストが自動的に失敗するため、アサーションは必要ありません。

最後のテストでは、実行時にパラメータを指定しながらオブジェクトをインスタンス化する方法を説明します。

@Test
public void givenClass__whenInstantiatesObjectsAtRuntime__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Constructor<?> cons1 = birdClass.getConstructor();
    Constructor<?> cons2 = birdClass.getConstructor(String.class);
    Constructor<?> cons3 = birdClass.getConstructor(String.class,
      boolean.class);

    Bird bird1 = (Bird) cons1.newInstance();
    Bird bird2 = (Bird) cons2.newInstance("Weaver bird");
    Bird bird3 = (Bird) cons3.newInstance("dove", true);

    assertEquals("bird", bird1.getName());
    assertEquals("Weaver bird", bird2.getName());
    assertEquals("dove", bird3.getName());

    assertFalse(bird1.walks());
    assertTrue(bird3.walks());
}


Constructor

classの

newInstance

メソッドを呼び出し、必要なパラメータを宣言された順序で渡すことによって、クラスオブジェクトをインスタンス化します。その後、結果を必要な型にキャストします。


bird1

の場合は、

Bird

コードから自動的に名前をbirdに設定するデフォルトのコンストラクタを使用し、それをテストで確認します。

次に、名前とテストのみを使用して

bird2

をインスタンス化します。最後の2つのアサーションで見られるように、移動動作をデフォルトのfalseに設定しない場合は、覚えておいてください。


7. フィールドを検査する

これまでは、フィールドの名前だけを調べてきました。このセクションでは、実行時に値を取得および設定する方法を示します。

実行時にクラスのフィールドを調べるために使用される2つの主な方法があります。


getFields()

および

getField(fieldName)


getFields()

メソッドは、問題のクラスのアクセス可能なすべてのパブリックフィールドを返します。クラスとすべてのスーパークラスの両方のすべてのパブリックフィールドが返されます。

たとえば、

Bird

クラスでこのメソッドを呼び出すと、

Bird

自体はパブリックフィールドを宣言しないため、スーパークラス

Animal



CATEGORY

フィールドのみが取得されます。

@Test
public void givenClass__whenGetsPublicFields__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Field[]fields = birdClass.getFields();

    assertEquals(1, fields.length);
    assertEquals("CATEGORY", fields[0].getName());
}

このメソッドには

getField

という名前のバリアントもあります。これは、フィールドの名前を取得して1つの

Field

オブジェクトだけを返します。

@Test
public void givenClass__whenGetsPublicFieldByName__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Field field = birdClass.getField("CATEGORY");

    assertEquals("CATEGORY", field.getName());
}

スーパークラスで宣言され、子クラスで宣言されていないプライベートフィールドにアクセスすることはできません。これが、

name

フィールドにアクセスできない理由です。

ただし、

getDeclaredFields

メソッドを呼び出すことで、処理しているクラスで宣言されているプラ​​イベートフィールドを調べることができます。

@Test
public void givenClass__whenGetsDeclaredFields__thenCorrect(){
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Field[]fields = birdClass.getDeclaredFields();

    assertEquals(1, fields.length);
    assertEquals("walks", fields[0].getName());
}

フィールドの名前がわかっている場合は、他のバリアントも使用できます。

@Test
public void givenClass__whenGetsFieldsByName__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Field field = birdClass.getDeclaredField("walks");

    assertEquals("walks", field.getName());
}

フィールドの名前が間違っていたり、既存のフィールドに入力した場合は、

NoSuchFieldException

が返されます。

フィールドタイプは次のようになります。

@Test
public void givenClassField__whenGetsType__thenCorrect() {
    Field field = Class.forName("com.baeldung.reflection.Bird")
      .getDeclaredField("walks");
    Class<?> fieldClass = field.getType();

    assertEquals("boolean", fieldClass.getSimpleName());
}

次に、フィールド値にアクセスしてそれらを変更する方法を調べます。設定するだけでなく、フィールドの値を取得できるようにするには、まず

Field

オブジェクトの

setAccessible

メソッドを呼び出してアクセス可能に設定し、それにブール値の

true

を渡す必要があります。

@Test
public void givenClassField__whenSetsAndGetsValue__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Bird bird = (Bird) birdClass.newInstance();
    Field field = birdClass.getDeclaredField("walks");
    field.setAccessible(true);

    assertFalse(field.getBoolean(bird));
    assertFalse(bird.walks());

    field.set(bird, true);

    assertTrue(field.getBoolean(bird));
    assertTrue(bird.walks());
}

上記のテストでは、

walks

フィールドの値がtrueに設定される前に、その値がfalseであることを確認しています。


Field

オブジェクトを使用して、処理しているクラスのインスタンスと、そのオブジェクトにフィールドに含める新しい値を渡すことで値を設定および取得する方法に注目してください。


Field

オブジェクトに関して注意すべき重要なことの1つは、それが

public static

として宣言されている場合、それらを含むクラスのインスタンスは必要ないということです。そのようです:

@Test
public void givenClassField__whenGetsAndSetsWithNull__thenCorrect(){
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Field field = birdClass.getField("CATEGORY");
    field.setAccessible(true);

    assertEquals("domestic", field.get(null));
}


8検査方法

前の例では、メソッド名を調べるためだけにリフレクションを使用しました。

ただし、Javaリフレクションはそれよりも強力です。

Javaリフレクションを使用すると、コンストラクタの場合と同じように、

実行時

にメソッドを呼び出して、必要なパラメータを渡すことができます。同様に、それぞれのパラメータ型を指定することでオーバーロードされたメソッドを呼び出すこともできます。

フィールドと同じように、クラスメソッドを取得するために使用する2つの主要なメソッドがあります。

getMethods

メソッドは、クラスおよびスーパークラスのすべてのパブリックメソッドの配列を返します。

つまり、このメソッドを使用すると、

toString、hashCode



notifyAll

などの

java.lang.Object

クラスのパブリックメソッドを取得できます。

@Test
public void givenClass__whenGetsAllPublicMethods__thenCorrect(){
    Class<?> birdClass = Class.forName("com.baeldung.java.reflection.Bird");
    Method[]methods = birdClass.getMethods();
    List<String> methodNames = getMethodNames(methods);

    assertTrue(methodNames.containsAll(Arrays
      .asList("equals", "notifyAll", "hashCode",
        "walks", "eats", "toString")));
}

関心のあるクラスのパブリックメソッドだけを取得するには、

getDeclaredMethods

メソッドを使用する必要があります。

@Test
public void givenClass__whenGetsOnlyDeclaredMethods__thenCorrect(){
    Class<?> birdClass = Class.forName("com.baeldung.java.reflection.Bird");
    List<String> actualMethodNames
      = getMethodNames(birdClass.getDeclaredMethods());

    List<String> expectedMethodNames = Arrays
      .asList("setWalks", "walks", "getSound", "eats");

    assertEquals(expectedMethodNames.size(), actualMethodNames.size());
    assertTrue(expectedMethodNames.containsAll(actualMethodNames));
    assertTrue(actualMethodNames.containsAll(expectedMethodNames));
}

これらの各メソッドは、名前がわかっている単一の

Method

オブジェクトを返す特異なバリエーションを持っています。

@Test
public void givenMethodName__whenGetsMethod__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Method walksMethod = birdClass.getDeclaredMethod("walks");
    Method setWalksMethod = birdClass.getDeclaredMethod("setWalks", boolean.class);

    assertFalse(walksMethod.isAccessible());
    assertFalse(setWalksMethod.isAccessible());

    walksMethod.setAccessible(true);
    setWalksMethod.setAccessible(true);

    assertTrue(walksMethod.isAccessible());
    assertTrue(setWalksMethod.isAccessible());
}

個々のメソッドを取得し、それらがどのようなパラメータタイプを取るかを指定する方法に注目してください。パラメータ型をとらないものは、空の可変引数で取得され、単一の引数、メソッド名だけが残ります。

次に、実行時にメソッドを呼び出す方法を示します。

Bird

クラスの

walks

属性は

false

であることがデフォルトでわかっています。その

setWalks

メソッドを呼び出して

true

に設定します。

@Test
public void givenMethod__whenInvokes__thenCorrect() {
    Class<?> birdClass = Class.forName("com.baeldung.reflection.Bird");
    Bird bird = (Bird) birdClass.newInstance();
    Method setWalksMethod = birdClass.getDeclaredMethod("setWalks", boolean.class);
    Method walksMethod = birdClass.getDeclaredMethod("walks");
    boolean walks = (boolean) walksMethod.invoke(bird);

    assertFalse(walks);
    assertFalse(bird.walks());

    setWalksMethod.invoke(bird, true);

    boolean walks2 = (boolean) walksMethod.invoke(bird);
    assertTrue(walks2);
    assertTrue(bird.walks());
}

最初に

walks

メソッドを呼び出し、戻り型を適切なデータ型にキャストしてからその値を確認する方法に注目してください。その後、後で

setWalks

メソッドを呼び出してその値を変更し、もう一度テストします。


9結論

このチュートリアルでは、Java Reflection APIについて説明し、コンパイル時に内部の知識がなくても実行時にそれを使用してクラス、インタフェース、フィールド、およびメソッドを検査する方法を調べました。

このチュートリアルの完全なソースコードと例は私のhttps://github.com/eugenp/tutorials/tree/master/core-java-lang[Github]プロジェクトにあります。