13種類の保持方針で、実行時に見えるのは1つ
同じに3つのを付け、から何個見えるかを確かめます。見えるのは (RUNTIME) を付けて定義した1つだけです。アノテーションを自作するときは、どこまで残すかを定義の側で決めます。
2.class の中ではどう記録されているか
上の Target.class を で見たものです。RUNTIME のものは RuntimeVisibleAnnotations、@Retention を付けなかったものは RuntimeInvisibleAnnotations という欄に入り、SOURCE のものは のどこにもありませんでした。付けない場合は消えるのではなく、記録はされるがリフレクションに出てこない、という扱いです。
RuntimeVisibleAnnotations:0: #14(#15=s#16)KeptAtRuntime(value="a")RuntimeInvisibleAnnotations:0: #18(#15=s#19)DefaultRetention(value="b")
3コンストラクタの引数の型を実行時に読む
が何を受け取るかを実行時に調べる例で、引数のクラス(Repo、List、int)に加え、宣言に書いた List<String> の String まで読めます。一方、new した ArrayList<String> と ArrayList<Integer> は同じクラスでした。残るのは宣言に書かれた型で、の側はを持っていません。
4引数の名前は既定では残らない
型は実行時に読めますが、引数の名前は既定のコンパイルでは残らず、arg0、arg1 のような仮の名前が返ります。 に を付けてコンパイルすると、ソースに書いた名前が読めるようになります。下の出力は 25 で同じコードをコンパイルし直したときのものです。
repo : Repo namePresent=truenames : java.util.List namePresent=truelimit : int namePresent=true
5TypeScript のデコレータと型はどうなるか
同じ形を TypeScript で書いた対照実験です(typescript 7.0.2、Node 24.21.0、experimentalDecorators を有効にした旧方式のデコレータ)。デコレータは実行時に関数として呼ばれ、型は emitDecoratorMetadata を付けてコンパイルし、さらに reflect-metadata を読み込んだときだけ実行時に読めました。その場合もの Clock は Object、string[] は Array になっています。
$ diff out-plain/main.js out-meta/main.js...29c32,33< Injectable()---> Injectable(),> __metadata("design:paramtypes", [Repo, Object, Array, Number])$ node out-plain/main.jsdecorator called for: ServiceService.length (number of ctor params): 4design:paramtypes: undefined$ node -r reflect-metadata out-meta/main.jsdecorator called for: ServiceService.length (number of ctor params): 4design:paramtypes: [[class Repo],[Function: Object],[Function: Array],[Function: Number]]
// デコレータは、クラスが定義されるときに呼ばれる関数
function Injectable(): ClassDecorator {
return (target) => {
console.log("decorator called for:", (target as any).name);
};
}
interface Clock { now(): number } // コンパイル時にしか存在しない
class Repo {}
@Injectable()
class Service {
constructor(private repo: Repo, private clock: Clock, private names: string[], private limit: number) {}
}
console.log("Service.length (number of ctor params):", Service.length);
console.log("design:paramtypes:", (Reflect as any).getMetadata?.("design:paramtypes", Service));