JavaのTypeとTypesの使い方

JavaのTypeとTypes

JavaのTypeとTypesは、それぞれ異なる用途を持つ概念やクラスを指します。
以下にそれぞれの概要を示します。

Type

JavaのTypeは、Javaプログラム内で使用されるデータ型全般を指します。
これはプリミティブ型(int, float, booleanなど)や参照型(クラス、インターフェース、配列など)を含みます。
具体的には、以下のようなものがTypeに該当します:

プリミティブ型:
int, float, boolean, charなど
参照型:
String, Object, カスタムクラス、配列など
ジェネリック型:
List, Mapなど

Typeはプログラム内で変数の宣言時やメソッドの引数・戻り値の型指定時に使用されます。

Types

TypesはJavaの標準ライブラリ内にあるユーティリティクラスで、主にJavaの型に関連する操作を提供します。
このクラスはjavax.lang.model.utilパッケージに含まれており、コンパイル時のメタデータ処理やアノテーション処理に使用されます。
具体的には、以下のようなメソッドが提供されています:

asElement(TypeMirror t):
与えられた型を表すTypeMirrorオブジェクトを対応するElementに変換します。
isSameType(TypeMirror t1, TypeMirror t2):
2つの型が同じかどうかをチェックします。
isSubtype(TypeMirror t1, TypeMirror t2):
ある型が別の型のサブタイプかどうかをチェックします。
directSupertypes(TypeMirror t):
与えられた型の直接的なスーパークラスやスーパーメソッドを返します。

このクラスは主にアノテーションプロセッサやコンパイラプラグインの開発者が使用します。

まとめ

Type:
Javaのデータ型全般を指し、プリミティブ型や参照型が含まれます。
Types:
javax.lang.model.utilパッケージ内のユーティリティクラスで、型に関する操作を提供します。

Typesはインスタンス化が不可能

Typesクラスはインスタンス化が不可能です。
Typesクラスはインターフェースであり、直接インスタンス化することはできません。
代わりに、コンパイラAPIを通じて取得されます。

TypesインターフェースはJavaコンパイラAPIの一部で、型に関する様々な操作を提供します。
通常、Typesインスタンスはコンパイラのコンテキスト(アノテーションプロセッサなど)でProcessingEnvironmentから取得されます。

取得方法の例

Typesインターフェースのインスタンスは、アノテーションプロセッサで以下のように取得します。

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.util.Types;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.Element;
import javax.lang.model.SourceVersion;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeKind;
import java.util.Set;

public class MyProcessor extends AbstractProcessor {
    private Types typeUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        typeUtils = processingEnv.getTypeUtils();
    }

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        for (Element element : roundEnv.getElementsAnnotatedWith(MyAnnotation.class)) {
            TypeMirror typeMirror = element.asType();
            if (typeUtils.isSubtype(typeMirror, processingEnv.getElementUtils().getTypeElement("java.lang.Number").asType())) {
                // Do something with the subtype check
            }
        }
        return true;
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        return Set.of(MyAnnotation.class.getCanonicalName());
    }

    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

この例では、ProcessingEnvironmentのgetTypeUtilsメソッドを使ってTypesインターフェースのインスタンスを取得しています。
このTypesインスタンスを使って、型に関する様々な操作を行うことができます。

主なメソッド

Typesインターフェースには多くのメソッドがあり、型の操作や情報取得に使用されます。
主なメソッドの例をいくつか紹介します:

  • asElement(TypeMirror t): 型を要素に変換します。
  • isSameType(TypeMirror t1, TypeMirror t2): 2つの型が同じかどうかを確認します。
  • isSubtype(TypeMirror t1, TypeMirror t2): ある型が別の型のサブタイプかどうかを確認します。
  • directSupertypes(TypeMirror t): 型の直接のスーパークラスやインターフェースを取得します。

これらのメソッドは、コンパイル時に型に関する詳細なチェックや変換を行う際に非常に有用です。