倭マン's BLOG

くだらない日々の日記書いてます。 たまにプログラミング関連の記事書いてます。 書いてます。

いまさら!? Class クラス (7) : 特定のクラスに固有のメソッド

Java の Class クラスに定義されているメソッドを見ていくシリーズ(目次)。 今回は Class クラスに定義されているメソッドのうち、特定の型に特有のメソッドを見ていきます。 特定の型に特有のメソッドとは、例えば「配列に対して要素の型を返すメソッド」のようなものです。 このメソッドは、配列以外に対しては意味がなく、呼び出すと null を返します。

ここで扱うメソッドを列挙しておきましょう:

メソッド名 返り値 有意な型
getComponentType() Class<?> 配列
getEnumConstants() T[] 列挙型
getEnclosingConstructor()
getEnclosingMethod()
Constructor<?>
Method
ローカルクラス、無名クラス
getEnclosingClass() Class<?> メンバクラス、ローカルクラス、無名クラス
getDeclaringClass() Class<?> メンバクラス

配列

まずは配列に特有のメソッド。

メソッド名 返り値 有意な型 説明
getComponentType() Class<?> 配列 要素の型を返す

配列の型以外に対して呼び出すと null が返されます。 サンプルはこんな感じ:

assert String[].class.getComponentType() == String.class;

列挙型

次は列挙型に特有のメソッド。

メソッド名 返り値 有意な型 説明
getEnumConstants() T[] 列挙型 定義されている定数を配列として返す

列挙型の型以外に対して呼び出すと null が返されます。 サンプルはこんな感じ:

public enum MyEnum{
    JAVA, GROOVY, SCALA, VISAGE
}

MyEnum[] enumConsts = MyEnum.class.getEnumConstants();
    // 配列 [MyEnum.JAVA, MyEnum.GROOVY, MyEnum.SCALA, MyEnum.VISAGE] が返される

メンバクラス、ローカルクラス、無名クラス

最後はメンバクラス、ローカルクラス、無名クラスのようなトップレベルクラスでないクラスに特有のメソッド。 扱うメソッドは以下の4つ:

メソッド名 返り値 有意な型 Since
getEnclosingConstructor()
getEnclosingMethod()
Constructor<?>
Method
ローカルクラス、無名クラス 1.5
getEnclosingClass() Class<?> メンバクラス、ローカルクラス、無名クラス 1.5
getDeclaringClass() Class<?> メンバクラス 1.1

「有意な型」以外の型に対して呼び出すと null が返されます。 また、無名クラスのインスタンス化によってフィールドの初期化を行うとフィールドとして保持することができますが、このインスタンスから Class クラスを取得して getEnclosingConstructor(), getEnclosingMethod() メソッドを呼び出すとやはり null が返されます。

public interface MyInterface{}

public class MyClass{
    private static MyInterface MINE = new MyInterface(){};
}

Class<?> type = MyClass.MINE.getClass();
assert type.getEnclosingConstructor() == null;
assert type.getEnclosingMethod() == null;

getEnclosingConstructor(), getEnclosingMethod() メソッド
これらのメソッドは、対象とするローカルクラス、無名クラスがコンストラクタ内に定義されているか、メソッド内に定義されているかによって使い分けます。 メソッド内に定義されている場合は getEnclosingConstructor() は null を返します and vice versa

メソッド内に定義されているローカルクラスに関するサンプル:

public class MyTest extends TestCase{

    public void testLocalClass(){
        class MyLocalClass{}
        
        Class<?> type = MyLocalClass.class;
        Method m = type.getEnclosingMethod());    // メソッド MyTest.testLocalClass() が返される
        Constructor c = type.getEnclosingConstructor());    // null が返される
   }
}

メソッド内に定義されているので、getEnclosingConstructor() メソッドは null を返します。

getEnclosingClass(), getDeclaringClass() メソッド
これらの2つのメソッドはどちらもそのクラスを含むクラスを返すメソッドです。 一方、これら2つのメソッドの違いは、getDeclaringClass() は内部クラスに対してのみ意味があるのに対して、getEnclosingClass() はコンストラクタやメソッド内に定義されているローカルクラス、無名クラスに対しても、それらが定義されているクラスを返すという点です。

まずは内部クラス(メンバクラス)に関するサンプル:

public class MyClass{
    public static class MyMemberClass{}
}

Class<?> type = MyClass.MyMemberClass.class;
assert type.getEnclosingClass() == MyClass.class;
assert type.getDeclaringClass() == MyClass.class;
assert type.getEnclosingClass() == type.getDeclaringClass();

内部クラスに関しては、これら2つのメソッドは同じく MyClass.class を返します。

一方、ローカルクラスに関しては

public class MyTest extends TestCase{

    public void testLocalClass(){
        class MyLocalClass{}
        
        Class<?> type = MyLocalClass.class;
        assert type.getEnclosingClass() == MyTest.class;
        assert type.getDeclaringClass() == null
        assert type.getEnclosingClass() != type.getDeclaringClass();
   }
}

となり、異なる結果を返します。

Java言語仕様 第3版 (The Java Series)

Java言語仕様 第3版 (The Java Series)