【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;
}
}