主頁 > 後端開發 > 熬夜剛完的注解與反射

熬夜剛完的注解與反射

2021-10-27 09:45:49 後端開發

注解與反射

  • 1.反射的概述
  • 2.反射基本使用
    • 1.獲取Class的三種方法
    • 2.通過反射獲取構造方法
    • 3.通過反射獲取到屬性欄位
    • 4.通過反射獲取方法
  • 3.反射main方法
  • 4.使用反射讀取組態檔,呼叫方法
  • 5.使用反射跳過泛型機制檢測
  • 6.注解
    • 1.注解概念
    • 2.jdk自帶注解常用
    • 3.自定義開發注解
    • 4.元注解
    • 5.注解+反射案例
    • 1.模仿Spring的自動裝配功能
    • 2.獲取欄位上注解的屬性值
  • 7.列舉
    • 用法一:常量
    • 用法二:列舉
    • 用法三:列舉類中添加方法
    • 用法四:使用介面組織列舉

1.反射的概述

JAVA反射機制是在運行狀態中,對于任意一個類,都能夠知道這個類的所有屬性和方法;對于任意一個物件,都能夠呼叫它的任意一個方法和屬性;這種動態獲取的資訊以及動態呼叫物件的方法的功能稱為java語言的反射機制,
要想解剖一個類,必須先要獲取到該類的位元組碼檔案物件,而解剖使用的就是Class類中的方法.所以先要獲取到每一個位元組碼檔案對應的Class型別的物件.

反射是比較重要的一個知識,現在的大多數框架都使用得到了反射+注解的形式,對我們的程式進行封裝,讓我們開箱即用,大大的減少了我們的開發時間,提升了我們的開發效率,使用反射+注解使得我們的程式變得更加的靈活多變

反射就是把java類中的屬性和方法映射成與之對應的Java物件,一個類有:成員變數、方法、構造方法、包等等資訊,利用反射技術可以對一個類進行解剖,把這些組成一個完整類的成員,拆分為一個一個的java物件,
在這里插入圖片描述

在這里插入圖片描述

Class 類的實體表示正在運行的 Java 應用程式中的類和介面,也就是說jvm中每個實體都應該屬于某個Class物件與之對應,(包括基本資料型別)
Class 沒有公共構造方法Class 物件是在加載類時由 Java 虛擬機以及通過呼叫類加載器中的defineClass 方法自動構造的,也就是這不需要我們自己去處理創建,JVM已經幫我們創建好了,

**我們來看下Class類的一些方法:**當然太多,等下挑常用的講

Modifier and TypeMethod and Description
<U> 類<? extends U>asSubclass(類<U> clazz) 這個 物件來表示由指定的類物件表示的類的子類,
Tcast(Object obj) 施放一個目的是通過本表示的類或介面 物件,
booleandesiredAssertionStatus() 如果要在呼叫此方法時初始化該類,則回傳將分配給此類的斷言狀態,
static 類<?>forName(String className) 回傳與給定字串名稱的類或介面相關聯的 物件,
static 類<?>forName(String name, boolean initialize, ClassLoader loader) 使用給定的類加載器回傳與給定字串名稱的類或介面相關聯的 物件,
AnnotatedType[]getAnnotatedInterfaces() 回傳一個 AnnotatedType物件的陣列, AnnotatedType使用型別指定由此 AnnotatedType物件表示的物體的超級
AnnotatedTypegetAnnotatedSuperclass() 回傳一個 AnnotatedType物件,該物件表示使用型別來指定由此 物件表示的物體的 類,
<A extends Annotation>AgetAnnotation(類<A> annotationClass) 回傳該元素的,如果這樣的注釋 *,*否則回傳null指定型別的注釋,
Annotation[]getAnnotations() 回傳此元素上 存在的注釋,
<A extends Annotation>A[]getAnnotationsByType(類<A> annotationClass) 回傳與此元素相關 聯的注釋
StringgetCanonicalName() 回傳由Java語言規范定義的基礎類的規范名稱,
類<?>[]getClasses() 回傳包含一個陣列 表示所有的公共類和由此表示的類的成員介面的物件 物件,
ClassLoadergetClassLoader() 回傳類的類加載器,
類<?>getComponentType() 回傳 陣列的組件型別的Class,
Constructor<T>getConstructor(類<?>... parameterTypes) 回傳一個 Constructor物件,該物件反映 Constructor物件表示的類的指定的公共 函式,
Constructor<?>[]getConstructors() 回傳包含一個陣列 Constructor物件反射由此表示的類的所有公共構造 物件,
<A extends Annotation>AgetDeclaredAnnotation(類<A> annotationClass) 如果這樣的注釋 直接存在 ,則回傳指定型別的元素注釋,否則回傳null,
Annotation[]getDeclaredAnnotations() 回傳 直接存在于此元素上的注釋,
<A extends Annotation>A[]getDeclaredAnnotationsByType(類<A> annotationClass) 如果此類注釋 直接存在或 *間接存在,*則回傳該元素的注釋(指定型別),
類<?>[]getDeclaredClasses() 回傳一個反映所有被這個 物件表示的類的成員宣告的類和 物件的陣列,
Constructor<T>getDeclaredConstructor(類<?>... parameterTypes) 回傳一個 Constructor物件,該物件反映 Constructor物件表示的類或介面的指定 函式,
Constructor<?>[]getDeclaredConstructors() 回傳一個反映 Constructor物件表示的類宣告的所有 Constructor物件的陣列
FieldgetDeclaredField(String name) 回傳一個 Field物件,它反映此表示的類或介面的指定已宣告欄位 物件,
Field[]getDeclaredFields() 回傳的陣列 Field物件反映此表示的類或介面宣告的所有欄位 物件,
方法getDeclaredMethod(String name, 類<?>... parameterTypes) 回傳一個 方法物件,它反映此表示的類或介面的指定宣告的方法 物件,
方法[]getDeclaredMethods() 回傳包含一個陣列 方法物件反射的類或介面的所有宣告的方法,通過此表示 物件,包括公共,保護,默認(包)訪問和私有方法,但不包括繼承的方法,
類<?>getDeclaringClass() 如果由此 物件表示的類或介面是另一個類的成員,則回傳表示其宣告的類的 物件,
類<?>getEnclosingClass() 回傳呼層類的即時封閉類,
Constructor<?>getEnclosingConstructor() 如果此物件表示建構式中的本地或匿名類,則回傳表示底層類的立即封閉建構式的Constructor物件,
方法getEnclosingMethod() 如果此物件表示方法中的本地或匿名類,則回傳表示基礎類的即時封閉方法的方法物件,
T[]getEnumConstants() 回傳此列舉類的元素,如果此Class物件不表示列舉型別,則回傳null,
FieldgetField(String name) 回傳一個 Field物件,它反映此表示的類或介面的指定公共成員欄位 物件,
Field[]getFields() 回傳包含一個陣列 Field物件反射由此表示的類或介面的所有可訪問的公共欄位 物件,
Type[]getGenericInterfaces() 回傳 Type表示通過由該物件所表示的類或介面直接實作的介面秒,
TypegetGenericSuperclass() 回傳 Type表示此所表示的物體(類,介面,基本型別或void)的直接超類
類<?>[]getInterfaces() 確定由該物件表示的類或介面實作的介面,
方法getMethod(String name, 類<?>... parameterTypes) 回傳一個 方法物件,它反映此表示的類或介面的指定公共成員方法 物件,
方法[]getMethods() 回傳包含一個陣列 方法物件反射由此表示的類或介面的所有公共方法 物件,包括那些由類或介面和那些從超類和超介面繼承的宣告,
intgetModifiers() 回傳此類或介面的Java語言修飾符,以整數編碼,
StringgetName() 回傳由 物件表示的物體(類,介面,陣列類,原始型別或空白)的名稱,作為 String
軟體包getPackage() 獲取此類的包,
ProtectionDomaingetProtectionDomain() 回傳 ProtectionDomain
URLgetResource(String name) 查找具有給定名稱的資源,
InputStreamgetResourceAsStream(String name) 查找具有給定名稱的資源,
Object[]getSigners() 獲得這個類的簽名者,
StringgetSimpleName() 回傳源代碼中給出的基礎類的簡單名稱,
類<? super T>getSuperclass() 回傳 表示此所表示的物體(類,介面,基本型別或void)的超類
StringgetTypeName() 為此型別的名稱回傳一個內容豐富的字串,
TypeVariable<類<T>>[]getTypeParameters() 回傳一個 TypeVariable物件的陣列,它們以宣告順序表示由此 GenericDeclaration物件表示的通用宣告宣告的型別變數,
booleanisAnnotation() 如果此 物件表示注釋型別,則回傳true,
booleanisAnnotationPresent(類<? extends Annotation> annotationClass) 如果此元素上 存在指定型別的注釋,則回傳true,否則回傳false,
booleanisAnonymousClass() 回傳 true當且僅當基礎類是匿名類時,
booleanisArray() 確定此 物件是否表示陣列類,
booleanisAssignableFrom(類<?> cls) 確定由此 物件表示的類或介面是否與由指定的Class 表示的類或介面相同或是超類或 介面,
booleanisEnum() 當且僅當該類在源代碼中被宣告為列舉時才回傳true,
booleanisInstance(Object obj) 確定指定的Object是否與此 Object表示的物件分配
booleanisInterface() 確定指定 物件表示介面型別,
booleanisLocalClass() 回傳 true當且僅當基礎類是本地類時,
booleanisMemberClass() 回傳 true當且僅當基礎類是成員類時,
booleanisPrimitive() 確定指定 物件表示一個基本型別,
booleanisSynthetic() 如果這個類是一個合成類,回傳true ; 回傳false其他,
TnewInstance() 創建由此 物件表示的類的新實體,
StringtoGenericString() 回傳描述此 的字串,包括有關修飾符和型別引數的資訊,
StringtoString() 將物件轉換為字串,

2.反射基本使用

User:案例類

package test;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-10-23-0:00
 * @Version:1.0
 * @Description:
 */
public class User {

    private int id;
    private int age;
    private String name;
    private String sex;

    public static List<User> getUserList(){
        List<User> userList = new ArrayList<>();
        userList.add(new User(1,29,"小明","男"));
        userList.add(new User(2,21,"小王","男"));
        userList.add(new User(3,18,"小李","女"));
        userList.add(new User(4,23,"小華","女"));
        userList.add(new User(7,50,"小花","女"));
        userList.add(new User(5,50,"小k","男"));
        userList.add(new User(6,60,"小浪","女"));

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

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

    }
    public String getSex() {
        return sex;
    }

    public void setSex(int id) {
        this.sex = sex;
    }
    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;
    }

    public String getName() {
        return name;
    }

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

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

    /**
     *  獲取一個User物件
     * @return
     */
    public User getUser(){
        return new User(1,29,"小明","男");
    }

}

1.獲取Class的三種方法

// 1.使用Object的方法getClass(),Object是所有類的父類,那么任何一個物件,都應該有getClass()方法
        User u = new User();
        Class<? extends User> uClass = u.getClass();

//2.任何資料型別都包含了一個class屬性,型別.class的方式
        Class<User> aClass = User.class;
        
//3.常用的 Class.classFrom(String arg),傳遞一個String型別的從類路徑到該類的具體路徑
// Class.forName("test.User") : 這個代碼會導致我們的靜態代碼塊加載,如果只是想執行某個類的靜態代碼塊,那么可以使用該方法
        Class<?> bClass = Class.forName("test.User");

獲取到某個類的Class物件有什么用?

我們可以通過該類的class物件,通過newInstance() 方法對該類進行實體化,不用我們手動去new,注意該方法,默認呼叫的是無參構造方法,如果一個類沒有任何構造方法,默認有一個無參構造,如果你重寫了有參構造,記得無參構造一定要帶上,否則newInstance() 方法將創建物件失敗,

User user = (User)bClass.newInstance();

2.通過反射獲取構造方法

   @Test
    void test1() throws Exception{
// 獲取共有的構造方法(public進行修飾的方法),并且回傳一個 Constructor陣列
        Constructor<?>[] constructors = User.class.getConstructors();
        for (Constructor constructor: constructors){
            System.out.println(constructor);
        }
        System.out.println("----------------------------------------------");

// 獲取指定某個構造方法,不傳遞任何引數,默認獲取無參構造,如果要獲取有參的需要跟上引數型別,必須和構造方法中引數順序一致
        Constructor<User> constructor1 = User.class.getConstructor(); // 獲取無參構造
        System.out.println("無參構造="+constructor1);

        System.out.println("----------------------------------------------");

        Constructor<User> constructor2 = User.class.getConstructor(String.class); // 獲取有參構造 User(String name)
        System.out.println("有參構造="+constructor2);

        System.out.println("----------------------------------------------");

// 獲取私有、受保護、默認、公有的構造方法,并且回傳一個 Constructor陣列
        Constructor<?>[] dc1 = User.class.getDeclaredConstructors();
        for (int i = 0; i < dc1.length; i++) {
            System.out.println("private="+dc1[i]);
        }

        System.out.println("----------------------------------------------");

// 獲取私有、受保護、默認、公有的構造方法,獲取單個的(自定義)
        Constructor dc2 = User.class.getDeclaredConstructor(int.class,String.class);
        System.out.println(dc2);

// 如果該構造方法是私有的,不能直接進行訪問,需要先設定為可訪問的
        if (!dc2.isAccessible()){ // 先判斷該方法是否可以進行訪問,如果不可以,進行修改,設定為可訪問的
            dc2.setAccessible(true); // 將private修飾的方法修飾為可訪問的
        }
// 呼叫 獲取到的構造方法,可以跟引數(不過要和獲取到的構造方法中的引數對應,否則拋出:IllegalArgumentException)
        User user1 = (User)dc2.newInstance(1, "張三");
        System.out.println("name="+user1.getName());

    }

3.通過反射獲取到屬性欄位

 @Test // 通過class物件獲取到屬性
    void test2() throws Exception{
        // 獲取到User類中的所有(公共)屬性 ,回傳一個 Field[]陣列
        Field[] fields = User.class.getFields();
        for (Field field : fields) {
            System.out.println("filed = "+field);
        }

        System.out.println("----------------------------------------");

        // 獲取到User類中單個屬性,回傳一個Field物件
        Field emailFiled = User.class.getField("email");
        System.out.println("emailFiled = "+emailFiled);

        System.out.println("----------------------------------------");

        // 獲取到User類中的所有屬性(私有、受保護、默認)
        Field[] df1 = User.class.getDeclaredFields();
        for (Field field : df1) {
            System.out.println("field = "+field);
        }

        System.out.println("----------------------------------------");

        // 獲取到User類中的單個的屬性(私有、受保護、默認)
        Field emailAttributes = User.class.getDeclaredField("email");
        System.out.println("emailAttributes ="+emailAttributes);

        System.out.println("----------------------------------------");

        // 通過反射實體化一個物件,并且獲取到該類中的欄位(email),并且給其賦值
        Class<User> userClass = User.class; // 獲得一個User.class物件
        User user = userClass.newInstance();
        Field[] declaredFields = userClass.getDeclaredFields(); // 獲取到user類中所有的屬性
        for (int i = 0; i < declaredFields.length; i++) { // 遍歷User類中所有的屬性,找到email屬性,為其賦值
          if (declaredFields[i].toString().contains("email")){
              declaredFields[i].setAccessible(true);//設定為可訪問的,以免程式出錯
              declaredFields[i].set(user,"admin@qq.com");
          }
        }
        System.out.println(user.email);
    }

4.通過反射獲取方法



    @Test // 同過class物件獲取到類中的所有方法,以及呼叫方法
    void test3() throws Exception{

        // 獲取到User類中所有的public方法,包括父類的
        Method[] methods = User.class.getMethods();
        for (Method method : methods) {
            System.out.println(" method = "+method);
        }

        System.out.println("----------------------------------------");

        // 獲取到User類中單個的public方法,包括父類的
        Method equals = User.class.getMethod("equals", Object.class);
        System.out.println("equals ="+equals);

        System.out.println("----------------------------------------");

        // 獲取到User類中所有的(私有、受保護、默認)方法
        Method[] methods2 = User.class.getDeclaredMethods();
        for (Method method : methods2) {
            System.out.println(" method = "+method);
        }

        System.out.println("----------------------------------------");

        // 獲取到User類中單個的(私有、受保護、默認)方法
        Method select = User.class.getDeclaredMethod("select", int.class);
        System.out.println("select ="+select);

        // 獲取到某個類中的方法,并且查詢到select方法,然后執行
        // invoke(呼叫物件,引數) :注意引數一定要匹配
        Class<User> userClass = User.class;
        User user = userClass.newInstance();
        Method[] dm = userClass.getDeclaredMethods();
        for (int i = 0; i < dm.length; i++) { // 這里怎么多條件只是練習下api而已
            if (dm[i].getName().equals("select")&&dm[i].getParameterCount()==1&& dm[i].getReturnType().getName().equals("java.lang.String")){
                //if (dm[i].toString().contains("select(int)")) // 這樣寫也是ok的
                dm[i].setAccessible(true); //設定為可訪問的
                // executeResult:就是我們方法呼叫完后的執行結果
                Object executeResult = dm[i].invoke(user, 123456);
                System.out.println("執行結果 = "+executeResult);

            }
        }

    }

3.反射main方法

  public class MyTest {
    public static void main(String[] args) {

        System.out.println("hello world");
    }  
  }
@Test // 反射main方法
    void test4() throws Exception{
        Class<MyTest> testClass = MyTest.class;
        Method main = testClass.getDeclaredMethod("main",String[].class);
        main.setAccessible(true);
        Object args = new String[]{"1"};
        main.invoke(testClass.newInstance(),args);
    }

4.使用反射讀取組態檔,呼叫方法

info.properties:內容 注意idea專案中的當前位置是,當前程序路徑下,

user=test.User
method=select

    @Test // 讀取組態檔,創建物件,并且呼叫方法
    void test5() throws Exception{
        Properties properties = new Properties();
        // 獲取到組態檔流
        FileReader reader = new FileReader("src/main/resources/info.properties");
        // 將組態檔流加載到 Properties 中
        properties.load(reader);

        // 從info.properties中獲取到user的資訊,并且得到User的class物件
        Class<?> aClass = Class.forName(properties.get("user").toString());
        // 利用反射實體化User物件
        Object object = aClass.newInstance();
        // 獲取到User類中的select方法
        Method select = aClass.getDeclaredMethod(properties.get("method").toString(), int.class);
        // 設定為可訪問的
        select.setAccessible(true);
        // 呼叫select方法,并且獲取回傳結果
        Object executeResult = select.invoke(object,1);
        System.out.println("executeResult = "+executeResult);

    }

5.使用反射跳過泛型機制檢測

    @Test  // 使用反射跳過泛型機制檢測
    void test6() throws  Exception{
      ArrayList<String> list = new ArrayList<>();
      list.add("admin");
      list.add("root");

      //list.add(new User(10,20,"admin")); //因為泛型機制的原因,此處不能添加User型別的資料,只能添加String型別的資料
      //獲取ArrayList的Class物件,反向的呼叫add()方法,添加資料
      Class listClass = list.getClass(); 
      //獲取add()方法
      Method method = listClass.getMethod("add", Object.class);
      //呼叫add()方法
      method.invoke(list, new User(10,20,"admin"));
      
      for(Object value : list){
          System.out.println("value = "+value);
      }

    }

6.注解

1.注解概念

注解(注釋,標注,Annotation)的作用 ?
如果要對于注解的作用進行分類,我們可以根據它所起的作用,大致可分為三類:
撰寫檔案:通過代碼里標識的元資料生成檔案,
代碼分析:通過代碼里標識的元資料對代碼進行分析,
編譯檢查:通過代碼里標識的元資料讓編譯器能實作基本的編譯檢查,

注解出現的位置
Annotation(注解)是JDK5.0及以后版本引入的,它可以用于創建檔案,跟蹤代碼中的依賴性,甚至執行基本編譯時檢查,從某些方面看,Annotation 就像修飾符一樣被使用,并應用于包、型別、構造方法、方法、成員變數、引數、本地變數的宣告中,這些資訊被存盤在Annotation的“name=value”結構對中,

注解成員屬性
Annotation的成員在Annotation型別中以無引數的方法的形式被宣告,其方法名和回傳值定義了該成員的名字和型別,在此有一個特定的默認 語法:允許宣告任何Annotation成員的默認值,一個Annotation可以將name=value對作為沒有定義默認值的Annotation 成員的值,當然也可以使用name=value對來覆寫其它成員默認值,這一點有些近似類的繼承特性,父類的建構式可以作為子類的默認建構式,但是也 可以被子類覆寫,

注解生命周期分類

原始碼注解:注解只在原始碼中存在,編譯成.class檔案就不存在了,
編譯時注解:注解在原始碼和.class檔案中都存在,(例如:JDK的三個注解)
運行時注解:在運行階段還起作用,甚至會影響運行邏輯的注解,

注解不會影響程式代碼的執行
Annotation 能被用來為某個程式元素(類、方法、成員變數等)關聯任何的資訊,需要注意的是,這里存在著一個基本的規則:Annotation不能影響程式代碼的執行,無論增加、洗掉 Annotation,代碼都始終如一的執行,另外,盡管一些Annotation通過java的反射api方法在運行時被訪問,而java語言解釋器在作業時忽略了這些Annotation,正是由于java虛擬機忽略了Annotation,導致了Annotation型別在代碼中是“不起作用”的; 只有通過某種配套的工具才會對Annotation型別中的資訊進行訪問和處理

2.jdk自帶注解常用

@Override:表示子類覆寫了父類的方法
@Deprecation:表示方法已經過時,方法上有橫線,使用時會有警告,
@author: 標明開發該類模塊的作者
@version: 標明該類模塊的版本
@see: 參考轉向,也就是相關主題
@param: 對方法中某引數的說明
@return: 對方法回傳值的說明
@exception: 對方法可能拋出的例外進行說明
@throws: 拋出的例外
@since:描述文本
@FunctionalInterface: 表示該介面是一個函式式介面,并且可以作為Lambda運算式引數傳入

@SuppviseWarnings: 表示關閉一些警告資訊(通知java編譯器忽略特定的編譯警告)

SuppviseWarnings:詳細引數如下:

屬性值描述
all抑制所有警告
boxing抑制裝箱、拆箱操作時候的警告
cast抑制映射相關的警告
dep-ann抑制啟用注釋的警告
deprecation抑制過期方法警告
fallthrough抑制確在switch中缺失breaks的警告
finally抑制finally模塊沒有回傳的警告
hiding抑制相對于隱藏變數的區域變數的警告的步驟
incomplete-switch忽略沒有完整的switch陳述句
nls忽略非nls格式的字符
null忽略對null的操作
rawtypes使用generics時忽略沒有指定相應的型別
restriction抑制與不鼓勵或禁止參考的使用相關的警告
serial忽略在serializable類中沒有宣告serialVersionUID變數
static-access抑制不正確的靜態訪問方式警告
ic-access抑制子類沒有按最優方法訪問內部類的警告
unchecked抑制沒有進行型別檢查操作的警告
unqualified-field-access抑制沒有權限訪問的域的警告
unused抑制沒被使用過的代碼的警告

3.自定義開發注解

自定義注解的語法規則

  • 使用@interface關鍵字定義注解,注意關鍵字的位置
    使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation介面,由編譯程式自動完成其他細節,在定義注解時,不能繼承其他的注解或介面,
  • 成員以無引數無例外的方式宣告,注意區別一般類成員變數的宣告, 其中的每一個方法實際上是宣告了一個配置引數,方法的名稱就是引數的名稱
  • 可以使用default為成員指定一個默認值,如上所示
  • 成員屬性型別是受限的,合法的型別包括原始型別以及String、Class、Annotation、Enumeration (JAVA的基本資料型別有8種:
    byte(位元組)、short(短整型)、int(整數型)、long(長整型)、float(單精度浮點數型別)、double(雙精度浮點數型別)、char(字符型別)、boolean(布爾型別)
  • 注解類可以沒有成員,沒有成員的注解稱為標識注解,例如JDK注解中的@Override、@Deprecation
  • 如果注解只有一個成員,并且把成員取名為value(),則在使用時可以忽略成員名和賦值號“=” 如果成員名 不為value,則使用時需指明成員名和賦值號"=",

自定義注解初識

// 自定義一個MyAnnotation注解,該注解中有一個className屬性成員
public @interface MyAnnotation {
    String className();
}

在其他類中使用該注解(后面會說到如何去獲取注解,以及注解中的屬性)

@MyAnnotation(className = "java.lang.reflect.Field")
public class MyTest2 {

注解中的 default關鍵字:

// 自定義一個MyAnnotation注解
public @interface MyAnnotation {
    String className();
    int userId() default 1004; // 增加一個 userId屬性,并且設定默認值為:1024
}

@MyAnnotation(className = "java.util.UUID") // 不寫userId也可以,使用我們設定的默認值:1024
class MyAnnotationTest{
    
}

成員屬性至有一個,且名稱為 value的特性

// 自定義一個MyAnnotation注解
public @interface MyAnnotation {
   String value();
}

//注解中只有一個成員屬性,且名稱為value,可以不用謝屬性名,當然也可以寫為:value = "simpleType"
@MyAnnotation(value = "simpleType") 
class MyAnnotationTest{

}

當注解的成員屬性是陣列的時候

// 自定義一個MyAnnotation注解
public @interface MyAnnotation {
 
   String[] dataType(); //成員屬性使用陣列的形式
}

// 當注解成員屬性是陣列時:dataType = {屬性值1,屬性值2,屬性值3,......}
@MyAnnotation(dataType = {"java","php","javaScript"})
class MyAnnotationTest{
 
}

注解中使用列舉類

// 自定義一個MyAnnotation注解
public @interface MyAnnotation {

    Color[] colorType();
}

// 當注解成員屬性是陣列時:dataType = {屬性值1,屬性值2,屬性值3,......}
@MyAnnotation(colorType={Color.BLACK,Color.GREEN})
class MyAnnotationTest{

}

// 定義顏色列舉型別
enum  Color{
   READ,GREEN,BLACK,WHITE;
}

4.元注解

什么是元注解?簡單的來說,就是注解的注解,也就是用來描述我們自定義的注解的注解,聽起來有點像套娃的感覺,其實注解,就是一個標簽,就像是商品一樣,貼上了標簽,對這個商品進行描述,比如說:價格呀,生產日期啊等等,我們的注解也是如此,可以對一個類,一個方法,一個屬性等等進行描述,我們可以獲取到他們上面是否包含有該注解,或者是獲取到他們上面的注解來指向某些邏輯,就像是我們的spring框架一樣,使用 @Autowired注解一樣,讓我們的物件進行自動裝配,使用注解+反射的開發形式,大大的提高了開發效率,代碼的靈活性,可重復性,

1.@Target

@Target說明了Annotation所修飾的物件范圍:即注解的作用域,用于說明注解的使用范圍(即注解可以用在什么地方,比如類的注解,方法注解,成員變數注解等等)簡單的來說,就是你自己定義的注解可以出現在什么位置都是由@Target注解來決定的如果沒有使用@Target進行描述:那么自定義的的注解可以應用于程式的任何位置

java.lang.annotation.ElementType這個列舉中規定@Target的取值范圍以及作用

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    // 類,介面,注解,列舉
    TYPE,

    /** Field declaration (includes enum constants) */
    // 成員屬性,列舉型常量
    FIELD,

    /** Method declaration */
    // 只能出現在方法上
    METHOD,

    /** Formal parameter declaration */
    // 只能用于形參宣告
    PARAMETER,

    /** Constructor declaration */
    // 只能用于構造方法上
    CONSTRUCTOR,

    /** Local variable declaration */
    // 區域變數宣告
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    // 注解型別宣告
    ANNOTATION_TYPE,

    /** Package declaration */
    // 用于包描述
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    // 引數型別宣告
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    // 型別使用
    TYPE_USE
}

2.@Retention

@Retention定義了該Annotation被保留的時間長短:

  1. 某些Annotation僅出現在源代碼中,編譯器在編譯時丟棄;
  2. 某些Annotation被編譯在class檔案中;編譯在class檔案中的Annotation可能會被虛擬機忽略,
  3. 某些Annotation在class被裝載時將被讀取(請注意并不影響class的執行,因為Annotation與class在使用上是被分離的),
    使用這個meta-Annotation可以對 Annotation的“生命周期”限制,

@Retention的取值是在RetentionPoicy這個列舉中規定的

  • SOURCE:在源檔案中有效(即源檔案保留)
  • CLASS :在class檔案中有效(即class保留)
  • RUNTIME:在運行時有效(即運行時保留)

3.@Inherited

@Inherited 元注解是一個標記注解,@Inherited闡述了某個被標注的型別是被繼承的,如果一個使用了@Inherited修飾的Annotation型別被用于一個class,則這個Annotation將被用于該class的子類,
注意:@Inherited Annotation型別是被標注過的class的子類所繼承,類并不從它所實作的介面繼承Annotation,方法并不從它所多載的方法繼承Annotation,當@Inherited Annotation型別標注的Annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這種繼 承性,如果我們使用java.lang.reflect去查詢一個@Inherited annotation型別的annotation時,反射代碼檢查將展開作業:檢查class和其父類,直到發現指定的Annotation型別被發現, 或者到達類繼承結構的頂層,

@Inherited:也就是說,子類可以繼承父類的類上的注解

// 自定義注解
// 自定義一個MyAnnotation注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited // 表示 MyAnnotation 這個注解可以被子類鎖繼承
public @interface MyAnnotation {

    String name();

}


//測驗代碼
@MyAnnotation(name = "admin")
public class MyTest2 {
    
    @Test
    void test1() throws Exception{
        // 通過反射獲取到 MyTest3的class物件
        Class<MyTest3> aClass = MyTest3.class;
        Annotation[] annotations = aClass.getAnnotations();// 獲取自身和父親的注解
        // 得到注解的型別
        System.out.println(annotations[0].annotationType()); // interface test.MyAnnotation
    }
}
// 此處默認繼承父類的 @MyAnnotation(name = "admin")
class MyTest3 extends MyTest2{

}

  1. AnnotatedElement 介面

此類非常重要,我們需要通過反射獲取注解,那么久離不開這個介面,我們的Class類是實作了該介面的,那就說明,我們可以通過class物件來獲取到class成員上的注解,

來我們看下API:

Modifier and TypeMethod and Description
<T extends Annotation>TgetAnnotation(類<T> annotationClass) 回傳該元素的,如果這樣的注釋 *,*否則回傳null指定型別的注釋,
Annotation[]getAnnotations() 回傳此元素上 存在的注釋,
default <T extends Annotation>T[]getAnnotationsByType(類<T> annotationClass) 回傳與此元素相關 聯的注釋
default <T extends Annotation>TgetDeclaredAnnotation(類<T> annotationClass) 如果這樣的注釋 直接存在 ,則回傳指定型別的元素注釋,否則回傳null,
Annotation[]getDeclaredAnnotations() 回傳 直接存在于此元素上的注釋,
default <T extends Annotation>T[]getDeclaredAnnotationsByType(類<T> annotationClass) 如果此類注釋 直接存在或 *間接存在,*則回傳該元素的注釋(指定型別),
default booleanisAnnotationPresent(類<? extends Annotation> annotationClass) 如果此元素上 存在指定型別的注釋,則回傳true,否則回傳false,

5.注解+反射案例

1.模仿Spring的自動裝配功能

? MyAnnotation :自定義注解

import java.lang.annotation.*;


/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-10-24-19:53
 * @Version:1.0
 * @Description: 自定義注解
 */
// 自定義一個MyAnnotation注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target({ElementType.TYPE_USE,ElementType.FIELD})
public @interface MyAnnotation {

    String className()default "";
    Color[] coloType()default Color.RED; //默認紅色
    String tableName()default "";
    String attribute()default "";
    String Autowired()default "yes"; // yes表示自動裝配,no表示不自動裝備

}
enum  Color{
    RED,GREEN,BLACK,BLUE;
}

2.Student:物體類

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-10-24-21:48
 * @Version:1.0
 * @Description:
 */
public class Student {

    private int id;
    private String name;
    private String email;
    private int status;
    private static Student student;

    public String show(String message){
        System.out.println("Student類的 show(String message) 方法被呼叫");
        System.out.println("message = "+message);
        return " call success";
    }
    public Student(int id, String name, String email, int status) {
        this.id = id;
        this.name = name;
        this.email = email;
        this.status = status;
    }   public Student() {

    }

    /**
     * 單例模式,雙重檢測機制(多執行緒下安全)回傳一個student物件
     * @return 回傳一個單例的student物件
     */
    public static Student  getInstance(){
        if (student==null){
            synchronized (Student.class){
                if (student==null){
                    student= new Student();
                }
            }
        }
        return student;

    }
    public int getId() {
        return id;
    }

    public void setStudent(Student student) {
        this.student = student;
    }
    public Student getStudent() {
        return student;
    }

    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public int getStatus() {
        return status;
    }

    public void setStatus(int status) {
        this.status = status;
    }

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

MyTest2:核心方法init()

import org.junit.jupiter.api.Test;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-10-24-20:02
 * @Version:1.0
 * @Description:
 */
@MyAnnotation(Autowired = "yes")
public class MyTest2 {
    @MyAnnotation(Autowired = "yes") // 如果把屬性值改為 no,將呼叫失敗
    private static Student student;

    public static void init(){
    // 雖然這種方式比較復雜,也許我沒有設計的那么好,但是可以聯合注解和反射做一個小練習,
    // 對注解和反射有個理解(當然可以把這段代碼寫在靜態代碼塊中)
        try {
            Class<MyTest2> aClass = MyTest2.class;
            // 獲取到 MyTest2 中的student屬性
            Field studentFiled = aClass.getDeclaredField("student");
            studentFiled.setAccessible(true); // 將該欄位先設定為可訪問,以免后面使用到出錯
            // 判斷 MyTest2 中的student屬性中是否有MyAnnotation注解
            if (studentFiled.isAnnotationPresent(MyAnnotation.class)){
                // 獲取到注解中的屬性值
                String flag = studentFiled.getAnnotation(MyAnnotation.class).Autowired();
                // 如果注解中的屬性值==yes,那么久創建一個Student的實體物件,賦值給student
                if (flag.equals("yes")){
                    // 讀取config.properties組態檔中的studentClassName屬性值
                    Properties p = new Properties();
                    FileReader configFile = new FileReader("src/main/resources/config.properties");
                    p.load(configFile);
                    String className =  p.get("studentClassName").toString();
                    // 使用反射機制創建一個物件 賦值給student
                    Class<?> forName = Class.forName(className.trim());
                    student = (Student)forName.newInstance();

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("初始化例外");

        }
    }

    @Test
    void test1() throws Exception{
        init(); // 只要是呼叫成功我們可以直接執行以下代碼的
        // 如果斷言失敗,請在idea中的 jvm option中設定:-ea
        assert student!=null; // 斷言判斷student是否為空,如果為空拋出 java.lang.AssertionError 例外
        String result = student.show("hello world!");
        System.out.println("call result = "+result);
    }
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fbRIdAaR-1635165117962)(C:\Users\14823\AppData\Roaming\Typora\typora-user-images\image-20211024230433211.png)]

當然還有別的更好的辦法,話幾個小時看了下反射和注解,如果有總結不太到位的地方請多多諒解,

2.獲取欄位上注解的屬性值

import java.lang.annotation.*;


/**
 * Created with IntelliJ IDEA.
 *
 * @Author: compass
 * @Date: 2021-10-24-19:53
 * @Version:1.0
 * @Description: 自定義注解
 */
// 自定義一個MyAnnotation注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
public @interface MyAnnotation {

    String[] name()default "";
    String tableName()default "";
    String attribute()default "";
    String Autowired()default "yes"; // yes表示自動裝配,no表示不自動裝備
 


}
// 列舉類
enum  Color{
    RED,GREEN,BLACK,BLUE;
}


// 自定義一個MyAnnotation2注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@interface MyAnnotation2 {


    Color[] coloType() default Color.RED; //默認紅色


}

package test;

import org.junit.jupiter.api.Test;
import java.io.FileReader;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Properties;


public class MyTest2 {

    @MyAnnotation(Autowired = "yes") // 單個屬性
    private static Student student;

    // 使用自定義注解中帶有列舉型別陣列的屬性
    @MyAnnotation2(coloType = {Color.RED,Color.BLACK,Color.GREEN,Color.BLUE}) //列舉型別陣列
    String colorType;

    @MyAnnotation(name = {"admin","root","jack"}) //String型別陣列
    String name;
   
   

}

class MyTest3{

    // 獲取欄位屬性上列舉型別陣列的屬性值
    @Test
    void test2() throws Exception {
        Class<MyTest2> aClass = MyTest2.class;
        Field field = aClass.getDeclaredField("colorType");
        MyAnnotation2 annotation = field.getAnnotation(MyAnnotation2.class);
        Color[] colors = annotation.coloType();
        for (Color color : colors) {
            System.out.println(color);
        }
    }

    // 獲取欄位上String型別陣列的屬性值
    @Test
    void test3() throws Exception {
        Class<MyTest2> aClass = MyTest2.class;
        Field field = aClass.getDeclaredField("name");
        boolean b = field.isAnnotationPresent(MyAnnotation.class);
        System.out.println(Arrays.toString(field.getDeclaredAnnotation(MyAnnotation.class).name()));
    }

    // 獲取欄位上單個屬性值
    @Test
    void test4() throws Exception{
        Class<MyTest2> aClass = MyTest2.class;
        Field student = aClass.getDeclaredField("student");
        if ( student.isAnnotationPresent(MyAnnotation.class)){
            String value = student.getDeclaredAnnotation(MyAnnotation.class).Autowired();
            System.out.println("value="+value);
        }
    }
}



7.列舉

列舉是一種特殊的常量類,構造方法默認是強制私有化的,(感覺列舉也有點忘了,大概的記錄一下,不需要的可以直接跳過)

列舉型別的每個自定義必須采用常量的命名方式,每個常量型別的欄位屬性寫好注釋,明確資料的用途【列舉代碼撰寫規范】

用法一:常量

public enum Color {  
  RED, GREEN, BLANK, YELLOW  
} 

用法二:列舉

 
enum  Color{
    RED,GREEN,BLACK,BLUE;
}

@Test
    void test4(){
        Color color = Color.RED;
        switch (color){
            case RED:
                System.out.println("read");break;
            case BLACK:
                System.out.println("black");break;
            case BLUE:
                System.out.println("blue");break;
            default:
                System.out.println("green");
        }
    }

用法三:列舉類中添加方法

public enum Color {
    READ(1,"紅色"),GREEN(2,"綠色"),BLACK(3,"黑色"),BLUE(4,"藍色");
    private String name;
    private int index;

    // 構造方法
    Color(int index, String name) {
        this.index=index;
        this.name=name;
    }

    /**
     *  根據索引獲取名稱
     * @param index
     * @return
     */
    public static String getName(int index){
        for (Color value : Color.values()) {
            if (value.index==index){
               return  value.name;
            }
        }
        return null;
    }
    public String getName() {
        return name;
    }

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

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

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

class MyTest{

    public static void main(String[] args)  {

        // 根據列舉型別欄位獲取一個列舉型別物件
        Color color = Color.valueOf("READ");
        System.out.println("index="+color.getIndex());
        System.out.println("name="+color.getName());

        // 根據獲取到列舉類中的所有屬性
        Color[] values = Color.values();
        for (Color value : values) {
            System.out.println("item="+value);
        }
        Color black1 = Color.BLACK;
        Color black2 = Color.BLACK;
        // 是常量,所有無論獲取多少次都是相同的,比較可以使用 == ,不必使用 equals
        System.out.println(black1==black2);
        System.out.println(black1.equals(black2));
    }
}

用法四:使用介面組織列舉

 interface Food {
    // 水果
    enum FRUITS implements Food{
        APPLE,BANANA,GRAPE,PEAR
    }
    //喝的
    enum DRINK implements Food{
        WATER, COKE, COFFEE
    }
}
//實作列舉型別介面
class FoodImpl implements Food{

}

class MyTest2{
    public static void main(String[] args) {
        // 可以獲取到介面中定義的列舉型別組,以及組中定義的列舉屬性值
        Food[] drinks = FoodImpl.DRINK.values();
        System.out.println(Arrays.toString(drinks));

        // 可以獲取到介面中定義的列舉型別組,以及組中定義的列舉屬性值
        Food[] fruits = FoodImpl.FRUITS.values();
        System.out.println(Arrays.toString(fruits));

    }
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/337686.html

標籤:java

上一篇:真香!秋招一夜爆火的面試題庫,讓多人進了大廠,被各大廠封殺了

下一篇:Java面試復盤 | 位元組番茄小說三面全部通過

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more