私はオンラインJavaトレーニングに従事しており、Java Coreコースの再設計の一環として、トレーニング資料の一部を公開します。
オンライン教育プラットフォームudemy.comでScala for Java Developersコースも教えています(Coursera / EdXに似ています)。
私の教え方は
- 例の増加するシーケンスの構築
- 可能なアプリケーションを説明する
- 著者によって駆動されるロジックを説明します(可能な限り)
- さまざまな組み合わせの理解と実証を包括的にテストする多数のテスト(50〜100)を提供します。
- 自主研究室を提供
この記事は、パラグラフ#1(例のシーケンス)および#2(ユースケース)に続きます。
行こう!
ケーススタディ:「クラスバージョン」に関するメタ情報をユーザークラスに提供します。
反復#1:
インターフェイスの前に@を置くだけです。
public @interface Version {}
反復#2:
注釈には属性を設定できます。
public @interface Version { public int version(); }
使用時に記入
@Version(version = 42) public class MyClass {}
上記の要約は、以下と完全に同等です(公開なし)。 このアノテーションはインターフェースに似ています:スコープ修飾子がないことは自動的にpublicを意味します(クラスのようにprivateパッケージを意味しません)。
public @interface Version { int version(); }
保護されたプライベートで-コンパイルされていません
public @interface Version { protected int version(); } >> COMPILATION ERROR: Modifier 'protected' not allowed here
次に、パブリック修飾子なしでオプションを使用します
繰り返し#3:
valueという名前の属性を宣言する場合、使用時にそれを省略できます。
public @interface Version { public int value(); }
@Version(42) public class MyClass {}
できますが、昔ながらの方法
@Version(value = 42) public class MyClass {}
反復#4:
属性のデフォルト値を宣言できます。
public @interface Version { int value(); String author() default "UNKNOWN"; }
現在、2つのユースケースがあります。 だから
@Version(42) public class MyClass {}
またはそのように
@Version(value = 42, author = "Jim Smith") public class MyClass { }
しかし、そうではありません(聞いて、in辱して、はい)
@Version(42, author = "Jim Smith") public class MyClass {} >> COMPILATION ERROR: Annotation attribute must be of the form 'name=value'
反復#5:
属性は配列タイプを持つことができます。
public @interface Author { String[] value() default {}; }
@Author({"Anna", "Mike", "Sara"}) public class MyClass {}
しかし、一次元のみ
public @interface Author2D { String[][] value() default {}; } >> COMPILATION ERROR: Invalid type of annotation member
反復#6:
楽しいトリック:注釈-注釈属性
public @interface Version { int value(); String author() default "UNKNOWN"; }
public @interface History { Version[] value() default {}; }
このように適用されます
@History({ @Version(1), @Version(value = 2, author = "Jim Smith") }) public class MyClass {}
注釈には多くの制限があります。 それらのいくつかをリストします。
制約:属性タイプ
1.属性は次のタイプのみを持つことができます
- プリミティブ
- ひも
- クラスまたは「クラスのパラメータ化された呼び出し」
- 列挙型
- 注釈
- 上記のタイプの要素の配列
最後の点は、1次元配列のみが許可されているという事実として理解する必要があります。
それでは、制限内で行動しましょう
反復#7:
「通常の」Javaクラスを属性タイプとして使用することはできません(java.lang.Stringおよびjava.lang.Classを除く)、たとえばjava.util.Date
import java.util.Date; public @interface Version { Date date(); } >> COMPILATION ERROR: Invalid type for annotation member
ただし、注釈のメモ/構造をエミュレートできます
public @interface Date { int day(); int month(); int year(); }
public @interface Version { Date date(); }
@Date(year = 2001, month = 1, day = 1) public class MyClass {}
反復#8:
注釈属性は列挙型である場合があります。 気持が良いから、アノテーション宣言で宣言できます(インターフェイス宣言のように、enum、クラス、インターフェイス、アノテーション宣言があります)
public @interface Colored { public enum Color {RED, GREEN, BLUE} Color value(); }
import static net.golovach.Colored.Color.RED; @Colored(RED) public class MyClass {}
反復#9:
注釈属性は、クラスリテラルにすることができます。
バージョンの概要には、クラスの以前のバージョンへのリンクが含まれています。
public @interface Version { int value(); Class<?> previous() default Void.class; }
クラスの最初のバージョン
@Version(1) public class ClassVer1 {}
最初のバージョンを参照する2番目のバージョン
@Version(value = 2, previous = ClassVer1.class) public class ClassVer2 {}
//はい、普通の人はクラス名にクラスバージョンを含めないことを知っています。 しかし、実際の練習と一致する例を考え出すのがいかに退屈であるか知っていますか?
反復#10:
クラスリテラルを使用したささいな例で、ジェネリックに抵抗して追加できませんでした。
「シリアライザー」のインターフェースは、出力のバイトストリームにTのインスタンスを書き込むことができるものです
import java.io.IOException; import java.io.OutputStream; public interface Serializer<T> { void toStream(T obj, OutputStream out) throws IOException; }
MyClassクラス用の特定の「シリアライザー」
import java.io.IOException; import java.io.OutputStream; public class MySerializer implements Serializer<MyClass> { @Override public void toStream(MyClass obj, OutputStream out) throws IOException { throw new UnsupportedOperationException(); } }
特定のクラスに「シリアライザーを接着」する注釈
public @interface SerializedBy { Class<? extends Serializer> value(); }
まあ、MyClassクラス自体は、「そのシリアライザー」MySerializerによってシリアライズ可能としてマークされています
@SerializedBy(MySerializer.class) public class MyClass {}
反復#11:
複雑な例
public enum JobTitle { JUNIOR, MIDDLE, SENIOR, LEAD, UNKNOWN }
public @interface Author { String value(); JobTitle title() default JobTitle.UNKNOWN; }
public @interface Date { int day(); int month(); int year(); }
public @interface Version { int version(); Date date(); Author[] authors() default {}; Class<?> previous() default Void.class; }
そして最後に、アノテーションの使用
import static net.golovach.JobTitle.*; @History({ @Version( version = 1, date = @Date(year = 2001, month = 1, day = 1)), @Version( version = 2, date = @Date(year = 2002, month = 2, day = 2), authors = {@Author(value = "Jim Smith", title = JUNIOR)}, previous = MyClassVer1.class), @Version( version = 3, date = @Date(year = 2003, month = 3, day = 3), authors = { @Author(value = "Jim Smith", title = MIDDLE), @Author(value = "Anna Lea")}, previous = MyClassVer2.class) }) public class MyClassVer3 {}
制限:属性値はJVMコンパイル/ロード時定数です
クラスがコンパイルまたはJVMにロードされるときに、アノテーション属性値を計算できる必要があります。
public @interface SomeAnnotation { int count(); String name(); }
例
@SomeAnnotation( count = 1 + 2, name = MyClass.STR + "Hello" ) public class MyClass { public static final String STR = "ABC"; }
別の例
@SomeAnnotation( count = (int) Math.PI, name = "" + Math.PI ) public class MyClass {}
しかし、メソッド呼び出しはすでに実行中です。これはすでに禁止されています
@SomeAnnotation( count = (int) Math.sin(1), name = "Hello!".toUpperCase() ) public class MyClass {} >> COMPILATION ERROR: Attribute value must be constant
おわりに
これは、Javaの注釈記事の最初の部分です。 第二部では、次のトピックを検討します。
- 他の注釈の動作を変更する注釈:@ Target、@ Retention、@ Documented、@ Inherited
- コンパイラーとJVMの動作を変更するアノテーション:@ Deprecated、@ Override、@ SafeVarargs、@ SuppressWarnings
- Reflection APIを使用して注釈を読み取る
連絡先
Javaトレーニングをオンラインで行い( プログラミングコースはこちら) 、Java Coreコースの再設計の一環としてトレーニング資料の一部を公開しています 。 この記事では、視聴者の講義のビデオ録画をyoutubeチャンネルで見ることができます。おそらく、 チャンネルのビデオがより体系化されています 。
スカイプ:GolovachCourses
メール:GolovachCourses@gmail.com