中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java中注解、元注解怎么用

發布時間:2022-01-25 09:00:33 來源:億速云 閱讀:144 作者:小新 欄目:開發技術

這篇“Java中注解、元注解怎么用”除了程序員外大部分人都不太理解,今天小編為了讓大家更加理解“Java中注解、元注解怎么用”,給大家總結了以下內容,具有一定借鑒價值,內容詳細步驟清晰,細節處理妥當,希望大家通過這篇文章有所收獲,下面讓我們一起來看看具體內容吧。

注解

Java注解也稱Java標注,是jdk1.5(5.0)后的新特征。Java語言中的類、方法、變量、參數和包等都可以被標注。和Javadoc不同,Java注解可以通過反射獲取標注內容,在編譯器生成類文件時,標注可以被嵌入到字節碼中,Java虛擬機可以保留標注內容,在運行時可以獲取到標注內容,當然它也支持自定義Java標注

功能:用于說明程序

用途:一般用在框架中使用

格式:@AnnotationName

文檔注釋:

@param @return @Exception從根本上是一個注釋,不存在代碼編譯,不會生成對應的文檔

注解:

@Override并不是沒有編譯就有效果,是因為不管是Eclipse還是IDEA都可以預編譯Java代碼生成對應的.class文件的

注解作用

生成文檔

代碼中生成對應的JavaDoc API文檔

@param @return

【IDEA JavaDoc工具使用參數】

Other Command Line Arguments:-encoding utf-8 -charset utf-8

解決中文亂碼,因為IDEA默認編碼集為UTF-8 windows默認編碼集為 GBK

代碼檢查

繼承重寫,或者說接口遵從之后的實現中,存在@Override

代碼數據獲取:【小型框架】

通過反射獲取指定注解中的一些內容,例如:配置,數據,操作,驗證等

Java預定義的注解

@Override

重寫/實現方法的情況下,檢查方法聲明是否和父類或者接口中的方法聲明一致,強制格式檢查

@Deprecated

標記當前方法已過時

@SuppressWarnings(“all”)

壓制警告,可以用于一些代碼中存在明確無異常的情況下,壓制一些警告

Annotation注解屬性【難點】

屬性

開發實際使用注解的方式中,數據使用方式更加偏向于屬性概念

使用

  1. 書寫代碼中使用
    @MyAnnotation(id=1, name=“ocean”, age=16)

  2. 使用反射時,會涉及到getXXX方法
    通過屬性名獲取對應值的概念來完成的

實際上是利用abstract方法來完成屬性概念的

屬性使用的格式【實際按照方法格式操作】

  1. 屬性的值數據類型和對應的具體數據 => 返回值類型和返回的數據屬性類型支持:

    1. 基本數據類型

    2. String類型

    3. 其他數據類型

    4. enmu枚舉類型,一個帶有名字的常量,為了更好的閱讀性和操作

    5. 以上類型對應的數組

  2. 屬性值要求

    1. 如果屬性是數組類型, {}大括號保存,并且不同的內容,使用,隔開屬性的鍵名字 ==> 方法的名字

    2. 定義屬性時可以使用default關鍵字,加上默認值,該屬性在使用的過程中是沒有強制要求屬性值,如果沒有賦予屬性值,采用對應的默認值操作,如果賦值,使用對應值

    3. 如果注解中有且只有一個value屬性,或者說注解中除value屬性之外,都有默認值,不管是類,方法,成員變量,包使用當前注解是可以直接在括號內加入
      對應數據類型數值

Java中注解、元注解怎么用

自定義注解

格式:
	public @interface AnnotationName {
		屬性列表;
	}
	
Annotation注解是可以編譯得到對應的.class字節碼文件,驗證了注解是可以參與編譯過程的

通過反編譯工具可以得到一下內容
【Annotation本質】
public interface MyAnnotation1 extends java.lang.annotation.Annotation {
}

MyAnnotation1
	本質是一個interface,同時java.lang.annotation.Annotation 子接口
package cn.ocean888.a_annotation.MyAnnotation;

/**
 * 自定義注解!!!
 * public interface MyAnnotation1 extends java.lang.annotation.Annotation {
 * }
 *
 * @author Anonymous
 * @date 2020/3/10 11:01
 */
public @interface MyAnnotation1 {
    // 屬性 ==> 方法形式
}

元注解

基于注解的解釋,用來約束注解的的一些操作問題

@Retention

表示這個注解的保存方式,是只在代碼中,還是編入class文件中,或者是運行時可以通過反射訪問

RetentionPolicy.RUNTIME:當前注解會編譯生成對應的.class字節碼文件,并且可以加載到JVM中,參與代碼執行

RetentionPolicy.CLASS

RetentionPolicy.SOURCE:注解將被編譯器丟棄(該類型的注解信息只會保留在源碼里,源碼經過編譯后,注解信息會被丟棄,不會保留在編譯好的class文件里)

@Document

標記這些注解是否包含在用戶文檔中

是否可以通過JavaDoc工具,生成對應的API文檔

@Target

標記這個注解應該是那種Java成員

屬性:ElementType

TYPE:當前注解可以用于類聲明

METHOD:當前注解可以用于方法聲明位置

FIELD:當前注解可以用于成員變量聲明位置

@Inherited

標記這個注解是繼承于那個注解類(默認 注解不繼承于任何子類)

獲取類上的注解

Java獲取類上的注解有下面3個方法:

  • Class.getAnnotations() 獲取所有的注解,包括自己聲明的以及繼承的

  • Class.getAnnotation(Class< A > annotationClass) 獲取指定的注解,該注解可以是自己聲明的,也可以是繼承的

  • Class.getDeclaredAnnotations() 獲取自己聲明的注解、

java.lang.Class類的isAnnotation()方法用于檢查此Class是否為Annotation類型

java.lang.Class類的isAnnotationPresent()方法用于檢查此類中是否存在指定注釋類型的注釋

實例:

實例1:兩種屬性文件的加載的方式

Java中注解、元注解怎么用

1.properties

className = cn.ocean888.a_annotation.Person
id = 1
name = "ocean"

Person類

package cn.ocean888.a_annotation;

public class Person {
    Integer id;
    String name;

    public Person() {
    }

    public Person(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

第一種使用反射來完成

package cn.ocean888.a_annotation;

import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

public class Demo1 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException, NoSuchFieldException {
        Properties properties = new Properties();
        properties.load(new FileInputStream("./src/1.properties"));

        String className = properties.getProperty("className");
        String id = properties.getProperty("id");
        String name = properties.getProperty("name");
        System.out.println(className);

        /*
        使用反射的方法
         */
        Class<?> aClass = Class.forName(className);
        Person person = (Person) aClass.getConstructor().newInstance();
        System.out.println(person);

        Field declaredField = aClass.getDeclaredField("id");
        declaredField.setAccessible(true);
        declaredField.set(person, Integer.parseInt(id));

        Field declaredField2 = aClass.getDeclaredField("name");
        declaredField2.setAccessible(true);
        declaredField2.set(person, name);

        System.out.println(person);
    }
}

Java中注解、元注解怎么用

第二種使用反射加注解的方式來完成

自定義注解

package cn.ocean888.a_annotation;

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

// 聲明當前注解有且只能用于類名之上
@Target(ElementType.TYPE)
// 當前注解參與代碼運行
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotaion1 {
    // 屬性
    String className();
    int id();
    String name();
}

ReflectAnnotation.java

package cn.ocean888.a_annotation;

import java.lang.annotation.Annotation;

@MyAnnotaion1(className = "cn.ocean888.a_annotation.Person",
    id = 2,
    name = "ocean")
public class ReflectAnnotation {
    public static void main(String[] args) {
        // 加載ReflectAnnotation
        Class<ReflectAnnotation> cls = ReflectAnnotation.class;

        // 因為注解再類名之上,通過Class獲取對應的Annotation
        MyAnnotaion1 annotation = cls.getAnnotation(MyAnnotaion1.class);

        String s = annotation.className();
        int id = annotation.id();
        String name = annotation.name();

        System.out.println(s);
        System.out.println(id);
        System.out.println(name);
    }
}

Java中注解、元注解怎么用

實例2使用注解測試代碼運行

對Tools方法中帶有@Check注解標記的方法進行檢查

Java中注解、元注解怎么用

Tools.java

package cn.ocean888.a_annotation_checkMethod;

import java.util.ArrayList;

/**
 * 需要測試的方法
 */
public class Tools {
    @Check
    public void test1() {
        String str = null;
        System.out.println(str.toString());
    }

    @Check
    public void test2() {
        int[] arr = null;
        System.out.println(arr[5]);
    }

    @Check
    public void test3() {
        int[] arr = {1,2,3,4,5};
        System.out.println(arr[3]);
    }

    @Check
    public void test4() {
        ArrayList<Integer> integers = new ArrayList<>();
        System.out.println(integers.get(20).toString());
    }

    @Check
    public void test5() {
        throw new NullPointerException("NullPointException");
    }
}

Utils.java

package cn.ocean888.a_annotation_checkMethod;

public class Utils {
    @Check
    public void test() {
        throw new IndexOutOfBoundsException("下標越界");
    }
}

Check.java

package cn.ocean888.a_annotation_checkMethod;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 該注解沒有任何屬性,只是作為是否需要測試的標記
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}

ClassAnnotation.java

package cn.ocean888.a_annotation_checkMethod;

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

/**
 * 自定義注解
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ClassAnnotation {
    String className();
}

TestProject.java

package cn.ocean888.a_annotation_checkMethod;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 測試Tools類內的方法,如果方法帶有Check注解,執行測試并記錄異常
 */
@ClassAnnotation(className = "cn.ocean888.a_annotation_checkMethod.Tools")
public class TestProject {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, IOException {

        // 從注解中獲取對應的屬性
        Class<TestProject> testProjectClass = TestProject.class;
        // 獲取所有指定的注解
        ClassAnnotation annotation = testProjectClass.getAnnotation(ClassAnnotation.class);
        String s = annotation.className();
        // s = cn.ocean888.a_annotation_checkMethod.Utils

        Class<?> aClass = Class.forName(s);

        Object tools = aClass.getConstructor().newInstance();
        // 獲取所有Tools類內的方法,不包括父類方法
        Method[] declaredMethods = aClass.getDeclaredMethods();

        // 記錄錯誤出現次數
        int count = 0;
        long l = System.currentTimeMillis();
        BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("./src/log.txt"));

        // 遍歷方法數組
        for (Method declaredMethod : declaredMethods) {
            declaredMethod.setAccessible(true);

            // 判斷當前方法是否帶有注解@Check標記
            if (declaredMethod.isAnnotationPresent(Check.class)) {
                try {
                    declaredMethod.invoke(tools);
                } catch (Exception e) {
                    count += 1;

                    // 1.哪一個方法出現異常
                    bufferedWriter.write("方法:" + declaredMethod.getName());
                    bufferedWriter.newLine();
                    // 2.發生異常原因,獲取對應的類型
                    bufferedWriter.write("異常類型:" + e.getCause().getClass().getSimpleName());
                    bufferedWriter.newLine();
                    // 3.異常信息
                    bufferedWriter.write("異常信息:" + e.getCause().getMessage());

                    bufferedWriter.newLine();

                }
            }
        }

        long l1 = System.currentTimeMillis();
        bufferedWriter.write("出現錯誤的次數" + count);
        bufferedWriter.newLine();
        bufferedWriter.write("總耗時" + (l1 - l));

        bufferedWriter.close();
    }
}

代碼的靈活性在于可以對className直接進行替換

Java中注解、元注解怎么用

Java中注解、元注解怎么用

注解使用總結

  • 注解在大多數情況下,都是使用過程,而不是自定義,會使用到框架中預處理好的注解

  • 注解使用對象

    • 編譯器

    • 解析代碼

    • JVM運行代碼使用

  • 注解是一個標簽,有時候是做標記,有時候標記有屬性

注解和python裝飾器的區別

先說java的注解(Annotation),實際上是給語法元素打一個標記。比如你可以給一個函數打一個標記,給一個類打一個標記等等。Java只保證記錄這個標記,但是不會主動根據這給標記做任何事。

比如,你在Spring里,給一個私有成員打 @Autowired 這個標記。

public class XXXService {

@Autowired
private XXXXRepository xxxxRepository;

// ...
}

如果你不用Spring框架的話,不會有任何事情發生,直接訪問這個字段就是空。當如果你配置了合適的處理流程,而這個流程就會根據有沒有這個標記干活。比如你要求Spring “Auto Scan” 并且注入依賴,這個處理過程會用反射去讀哪些元素被做了某個特定標記。沒有標記就不理,有標記就注入。

python里的decorator是一個語法糖,是希望把“decorator”這個形式寫得更漂亮。比如,你想記錄一個函數開始執行之前和之后的log:

def foo():
print("Hello")

def logit(fn):
def inner():
print("before execute")
fn()
printf("after execute")
return inner

這時,你可以魔改以下foo的實現,用logit這個“裝飾器”來部分修改foo的行為,然后執行:

foo = logit(foo)
foo()

但python里的語法可以讓這個東西寫成:

@logit
def foo():
print("Hello")

foo()

也就是說,python這里的裝飾器是一個有邏輯的,可以執行的函數,只不過其寫法有些特殊要求;而Java里面的Annotation只是個標記,需要其他代碼來“根據標記執行“。

當然,裝飾器模式是個很通用的東西,無論是python,java還是其他語言都可以寫。只是python提供了特殊的語法糖而已。但java世界里做類似decorator的事情,希望動態魔改一個函數的行為,可以用動態代理或者AOP。

Java的Annotation因為相當于多加了一層(標記 + 處理邏輯),是一把雙刃劍。好處是,在不動代碼的情況下你可以通過外部配置來修改程序的行為。比如給一個函數打上@Test標。如果通過UT框架運行,這些打標的函數會被當作是測試用例;但如果外部直接用普通的main啟動,這些@Test就會沒有一樣,不會影響代碼本身的邏輯。但反過來,也容易引來一些問題。比如有的時候,你很難知道那個根據標記執行的邏輯是不是真的跑了。也許你哪里配置拼錯一個字,或者classpath少依賴一個包,就造成那個邏輯并沒有真的執行。這時從表面上也許很難看出來出錯了。

感謝您的閱讀,希望您對“Java中注解、元注解怎么用”這一關鍵問題有了一定的理解,具體使用情況還需要大家自己動手實驗使用過才能領會,快去試試吧,如果想閱讀更多相關知識點的文章,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

蓝山县| 湘阴县| 隆尧县| 宁国市| 宜宾县| 佛山市| 仁化县| 邵武市| 新津县| 蕉岭县| 宜兴市| 仲巴县| 黔西| 沙田区| 体育| 黎平县| 徐水县| 桐柏县| 龙川县| 通州区| 苏尼特左旗| 离岛区| 大城县| 广东省| 磐安县| 孙吴县| 林甸县| 绍兴县| 卓资县| 门源| 乌拉特中旗| 滕州市| 延津县| 即墨市| 阳城县| 高陵县| 张家界市| 天祝| 合作市| 东明县| 沙雅县|