1. 程式人生 > 其它 >第41天學習打卡(註解 內建註解 元註解 自定義註解 反射機制 )

第41天學習打卡(註解 內建註解 元註解 自定義註解 反射機制 )

技術標籤:java反射

註解Java.Annitation

什麼是註解

Annotation是從JDK5.0開始引入的新技術

Annotation的作用:

不是程式本身,可以對程式作出解釋。(這一點和註釋(comment)沒什麼區別)

可以被其他程式(比如:編譯器等)讀取。

Annotation的格式:

註解是以“@註釋名”在程式碼中存在的,還可以新增一些引數值,例如“@SuppressWarnings(value=“unchecked”).

Annotation在哪裡使用?

可以附加在package,class,method,field等上面,相當於給他們添加了額外的輔助資訊,我們可以通過反射機制程式設計實現對這些元資料的訪問。

內建註解

@Override:定義在java.lang.Override中,此註釋只適用於修辭方法,表示一個方法宣告打算重寫超類中的另一個方法宣告。

@Deprecated:定義在java.lang.Deprecated中,此註釋可以用於修辭方法,屬性,類,表示不鼓勵程式設計師使用這樣的元素,通常是因為它很危險或者存在更好的選擇。

@SuppressWarnings:定義在java.lang.SuppressWarnings中,用來抑制編譯時的警告資訊。

​ 與前兩個註釋有所不同,你需要新增一個引數才能正確使用,這些引數都是已經定義好了的,我們選擇性的使用就好了。

@SuppressWarnings
("all") @SuppressWarnings("unchecked") @SuppressWarnings(value={"unchecked","deprecation"}) 等等...
package com.kuang.annotation;

import javax.naming.MalformedLinkException;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("all"
) public class Test01 extends Object{ //@Override 重寫的註解 @Override public String toString() { return super.toString(); } @Deprecated public static void test(){ System.out.println("Deprecated"); } public void test02(){ List list = new ArrayList(); } public static void main(String[] args) { test(); } }

元註解

元註解的作用就是負責註解其他註解,Java定義了4個標準的meta-annotation型別,他們被用來提供對其他annotation型別作說明。

這些型別和它們所支援的類在java.lang.annotation包中可以找到。(@Target,@Retention,@Documented,@Inherited)

Target:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)
@Retention:表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期。
    (SOURCE<CLASS<RUNTIME)
@Document:說明該註解將被包含在javadoc中
@Inherited:說明子類可以繼承父類中的該註解
package com.kuang.annotation;

import java.lang.annotation.*;
import java.util.EnumMap;

//測試元註解
//一個類裡面只能有一個public
@MyAnnotation
public class Test02 {

    public void test(){

    }
}
//定義一個註解
//Target 表示我們的註解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})


//Retention 表示我們的註解在什麼地方還有效
//runtime>class>sources
@Retention(value = RetentionPolicy.RUNTIME)

//Documented 表示是否將我們的註解生成在JAVAdoc中
@Documented
//Inherited 子類可以繼承父類的註解
@Inherited
@interface  MyAnnotation{

}

自定義註解

使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation介面

分析:

@interface用來宣告一個註解,格式:[email protected]註解名{定義內容}—>在類裡面宣告的話要把public去掉

其中的每個方法實際上是聲明瞭一個配置引數。

方法的名稱就是引數的名稱。

返回值型別就是引數的型別(返回值只能是基本型別,Class,String,enum)

可以通過default來宣告引數的預設值

如果只有一個引數成員,一般引數名為value

註解元素必須要有值,我們定義註解元素時,經常使用空字串,0作為預設值

package com.kuang.annotation;

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

//自定義註解
public class Test03 {
    //去掉哪一個註解的預設值,就只用給那一個註解的預設值賦值就可以了,註解沒有順序
    //註解可以顯示賦值,如果沒有預設值,我們就必須給註解賦值
    @MyAnnotation2()
    public void test(){

    }
    @MyAnnotation3("秦")
    public void test2(){

    }
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    //註解的引數:引數型別 + 引數名();
    //加了default之後,@MyAnnotation()就可以不在裡面加引數 也可以賦值
    String name() default"";
    int age() default 0;
    int id() default -1;//如果預設值為-1,代表不存在,與indexof:如果找不到就返回-1 有異曲同工之妙

    String[] schools() default {"西部開源","清北"};

}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    //如果只有一個value,那麼上面的@MyAnnotation可以省略一個value直接寫值
    String value();

}

反射機制(Java.Reflection)

靜態VS動態語言

動態語言

是一類在執行時可以改變其結構的語言:例如新的函式、物件、甚至程式碼可以被引進,已有的函式可以被刪除或是其他結構上的變化。通俗點說就是在執行時程式碼可以根據某些條件改變自身結構。

主要動態語言:Object-C、C#、JavaScript、PHP、Python等

靜態語言

與動態語言相對應的,執行時結構不可變的語言就是靜態語言。如Java,C,C++,

Java不是動態語言,但Java可以稱之為”準動態語言“。即Java有一定的動態性,我們可以利用反射機制獲得類似動態語言的特性。Java的動態性讓程式設計的時候更加靈活。

Java Reflection

Reflection(反射)是Java被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API取得任何類的內部訊息,並能直接操作任意物件的內部屬性及方法。

Class c = Class.forName("java.lang.String")
    

載入完類之後,在堆記憶體的方法區中就產生了一個Class型別的物件(一個類只用一個Class物件),這個物件就包含了完整的類的結構資訊。我們可以通過這個物件看到類的結構。這個物件就像一面鏡子,透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射

image-20210218161544087

Java反射機制研究及應用

Java反射機制提供的功能

在執行時判斷任意一個物件所屬的類

在執行時構造任意一個類的物件

在執行時判斷任意一個類所具有的成員變數和方法

在執行時獲取泛型資訊

在執行時呼叫任意一個物件的成員變數和方法

在執行時處理註解

生成動態代理

Java反射優點和缺點

優點:

可以實現動態建立物件和編譯,體現出很大的靈活性

缺點:

對效能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什麼並且它滿足我們的要求。這類操作總是慢於直接執行相同的操作。

反射相關的主要API

java.lang.Class:代表一個類
java.lang.reflect.Method:代表類的方法
java.lang.reflect.Field:代表類的成員變數
java.lang.reflect.Constructor:代表類的構造器

Class類

在Object類中定義了以下的方法,此方法將被所有子類繼承

public final Class getClass()

以上的方法返回值的型別是一個Class類,此類是Java反射的源頭,實際上所謂反射從程式的執行結果來看也很好理解,即:可以通過物件反射求出類的名稱。

package com.kuang.reflection;
//什麼叫反射
public class Test02 extends Object{
    public static void main(String[] args) throws ClassNotFoundException {
        //通過反射獲取類的class物件
        Class c1 = Class.forName("com.kuang.reflection.User");
        System.out.println(c1);

        Class c2 = Class.forName("com.kuang.reflection.User");
        Class c3 = Class.forName("com.kuang.reflection.User");
        Class c4 = Class.forName("com.kuang.reflection.User");
        //一個類在記憶體中只有一個Class物件,所以其雜湊值是一樣的
        //一個類被載入後,類的整個結構都會被封裝在Clsaa物件中

        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());

    }
}
//實體類:類裡面只有屬性叫實體類 pojo, entity
class User{
    private String name;
    private int id;
    private int age;

    public User() {
    }

    public User(String name, int id, int age) {
        this.name = name;
        this.id = id;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

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