【Java】注解

注释

    • クラス・インターフェースなどの型、メンバーに付与できるマーク

アプリ本来のロジックとは直接関係しない付随情報をコードに追加できる
対象となる宣言の先頭に記述

“@Override”用于Java中的方法,表示此方法是从其父类继承并进行了重写。

    • 標準ライブラリで提供されるアノテーション

 

    • 対象メソッドが基底クラスのメソッドをオーバーライドしていることを宣言

 

    引数のミスでオーバーライドできてない時もコンパイラが警告してくれる
public class Person {
  private String firstName;
  private String lastName;

  public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    return String.format("名前は、%s %s です。",
        this.lastName, this.firstName);
  }

  public String getLastName() {
    return this.lastName;
  }

  public String getFirstName() {
    return this.firstName;
  }
}

@WebServlet注解

    • サーブレットとはサーバー環境でJavaアプリを実行するための基本技術の一種

 

    • サーブレットの基本的な構成情報

urlPatterns:サーブレットを呼ぶためのURL

initParams:サーブレットで利用できるパラメータ情報

注释的重点

    • アノテーション入れ子が可能

要素1個なら配列の{…}省略可能

urlPatterns = “/init-param”

属性名valuesは省略可能

@WebServlet (values=”init-param”)

@WebServlet (“init-param”)

属性がない場合、()省略可能

マーカーアノテーション(@Overrideなど)

標準註釋

@Override:基底クラスのメソッドを上書きしていることを宣言

@Deprecated:クラスやメンバーなどが非推奨であることを宣言

@SuppressWarnings:コンパイラー警告を抑制

@SafeVarargs:可変長引数の型安全を宣言

@FunctionalInterface:インターフェースを関数型インターフェースとして定義することを宣言

@不推荐使用的

    • クラス、メソッドなどが非推奨であることを宣言

IntegerコンストラクタはJava9以降で非推奨(since=”9″)

ドキュメンテーションでも記述

コンパイルは通るが警告がでる

/**
 * 中略
 * @deprecated
 * It is rarely appropriate to use this constructor. The static factory
 * {@link #valueOf(int)} is generally a better choice, as it is
 * likely to yield significantly better space and time performance.
 */

@Deprecated(since="9")
public Integer(int value) {
    this.value = value;
}

@抑制警告

特定範囲/種類のコンパイラー警告を非表示

他の本来確認すべき警告の見落としを防げる
意図して警告対象のコードを利用しているという意思表示

public class AnnotationBasic {

  public static Integer process() {
   @SuppressWarnings("deprecation")
    var i = new Integer(108);
   return i;
  }

  public static void main(String[] args) {
    System.out.println(process());
  }
}

@SafeVarargs

可変長引数の型安全を宣言し、警告が表示されない

ジェネリック型を可変長引数とすると警告が出る

あくまでも型安全であることを開発者が認識してるという宣言

自己做的注释

    • アノテーションは修飾子と違って自作できる

 

    • アノテーションは@interface命令で定義

@interface配下でアノテーションで利用できる属性を宣言

以下の@ClassInfoではバージョン属性をversion属性、value属性で指定する

@ClassInfo(version=”2.1″, description=”アノテーションテスト”)
@ClassInfo(version=”2.1″)

アノテーション構成情報宣言するメタアノテーションを記述

@Documented:javadocにアノテーション情報反映

@Target:アノテーションをどの要素に適用するか決める

@Inherited:アノテーションが派生クラスにも継承

@Retention:アノテーション情報をどのタイミングまで保持するか

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//構成情報宣言
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
//@interface命令でアノテーション定義
public @interface ClassInfo {
  //アノテーションで利用できる属性を宣言
  String value() default "";
  String version() default "";
  String description() default "";
}

在反思中使用批注

リフレクション(Reflection):コードの実行中に型情報取得、操作する
以下ではClass.forNameメソッドで指定した型情報をClassクラスで取得
マーカーアノテーション:アノテーションが保持する情報(属性)ではなくアノテーション存在そのものに関心がある

isAnnotationPresentメソッドでアノテーション有無確認

package mypackage;

//ClassInfoアノテーション指定
@ClassInfo(version = "2.1", description = "アノテーションの動作テスト")
// @ClassInfo("2.1")
public class AnnotationClient {
  public static void main(String[] args) throws ClassNotFoundException {
    //Classオブジェクトを経由して配下のメンバー取得
    var clazz = Class.forName("mypackage.AnnotationClient");
    //getAnnotationメソッドでクラスに付与されたアノテーション取得
    var info = (ClassInfo)
 clazz.getAnnotation(ClassInfo.class);
    System.out.println("バージョン:" +
        (info.value().equals("") ? info.version() : info.value()));
    System.out.println("説明:" + info.description());
  }
}

反射方法

对象创建

    • コンストラクタ経由でインスタンス生成

呼び出すコンストラクタをClassクラスのgetConstructorメソッドで生成

newInstanceメソッドで呼び出すことでオブジェクト生成

Array.newInstanceメソッドで配列生成

setメソッドで配列要素設定

import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

public class ReflectInstance {

  public static void main(String[] args) {
    try {
      //Fileクラス取得
      var clazz = File.class;

      //コンストラクタ経由でFileオブジェクト生成
      var c = clazz.getConstructor(String.class);
      var fl = c.newInstance("./data/data.txt");
      System.out.println(fl);

      //サイズ2の配列生成
      var list = (File[]) Array.newInstance(File.class, 2);
      Array.set(list, 0, fl);
      System.out.println(Arrays.toString(list));
    } catch (InstantiationException | IllegalAccessException |
        IllegalArgumentException | InvocationTargetException
        | NoSuchMethodException | SecurityException e) {
      e.printStackTrace();
    }
  }
}

获取所有方法

getMethodsメソッドでFileクラスのPublicメソッド列挙

publicメソッドをMethodオブジェクトの配列として返す

public以外も取りたいときはgetDeclaredMethodsメソッドで全メソッド取得

import java.io.File;

public class ReflectMethods {

  public static void main(String[] args) {
    //Fileクラス取得
    var str = File.class;
    //Fileクラス配下のpublicメソッドをgetNameでメソッド名列挙
    for (var m : str.getMethods()) {
      System.out.println(m.getName());
    }
  }
}

执行方法

    • Methodオブジェクトを介して実行

getMethodメソッドで個別のメソッドを取得し、invokeメソッドで実行

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ReflectInvoke {

  public static void main(String[] args) {
    try {
      //Fileクラス取得
      var clazz = File.class;
      //Fileオブジェクト生成
      var f1 = clazz.getConstructor(String.class).newInstance("./data/data.txt");
      var f2 = clazz.getConstructor(String.class).newInstance("./data/sample.txt");
      //renameToメソッド取得、実行
      Method m = clazz.getMethod("renameTo", File.class);
      System.out.println(m.invoke(f1, f2));
    } catch (NoSuchMethodException | SecurityException |
        InstantiationException | IllegalAccessException
        | IllegalArgumentException | InvocationTargetException e) {
      e.printStackTrace();
    }
  }
}

获取和设置字段

    • publicフィールドはgetFieldメソッドで取得

 

    • その他フィールドはgetDeclaredFiledメソッドで取得

 

    • 引数は取得したいフィールドの名前を指定

 

    • Fieldオブジェクト取得したらget/setメソッドでフィールド値を取得/設定

 

    • privateフィールドはそのままアクセスできないので、setAccessibleメソッドでアクセスを明示的に許可

 

    注意:リフレクションは低速
//PersonクラスのlastNameフィールド取得

import java.lang.reflect.InvocationTargetException;
import example.Person;

public class ReflectField {

  public static void main(String[] args) {
    try {
      var clazz = Person.class;
      var con = clazz.getConstructor(String.class, String.class);
      var p = con.newInstance("太郎", "山田");
      //フィールド取得
      var last = clazz.getDeclaredField("lastName");
      //privateフィールドへのアクセスを明示的に許可
      last.setAccessible(true);
      //get/setメソッドでフィールド値取得/設定
      last.set(p, "鈴木");
      System.out.println(last.get(p)); //鈴木
    } catch (NoSuchMethodException | SecurityException |
        InstantiationException | IllegalAccessException
        | IllegalArgumentException | InvocationTargetException |
        NoSuchFieldException e) {
      e.printStackTrace();
    }
  }
}

package example;
public class Person {
  private String firstName;
  private String lastName;
  public Person(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }
  @Override
  public String toString() {
    return String.format("名前は、%s %s です。",
        this.lastName, this.firstName);
  }
  public String getLastName() {
    return this.lastName;
  }
  public String getFirstName() {
    return this.firstName;
  }
}
广告
将在 10 秒后关闭
bannerAds