主頁 > 後端開發 > java注解與反射

java注解與反射

2023-05-31 08:08:28 後端開發

java注解與反射

  • java注解與反射十分重要,是很多框架的底層

注解(Annotataion)

  • 注解的作用:

       1. 不是程式本身,可以對程式作出解釋
       1. 可以被其他程式讀取
    
  • 注解的格式:@注釋名,如@override表示重寫方法,而且有些還可以添加一些引數值,如@SuppressWarnings(value="https://www.cnblogs.com/rainaftersummert/archive/2023/05/30/unchecjed")

  • 注解可以附加在package,class,method,field等上面,相當于添加了額外的輔助資訊,可以通過反射機制編程實作對這些元資料的訪問

內置注解

  1. @Override:重寫方法
  2. @Deprecated:表示不被鼓勵使用或者已廢棄已過時
  3. @SuppressWarning:用來抑制編譯時的警告資訊,但是需要添加一個或多個引數:如("all"),("unchecked")等,平時最好還是不要用這個

使用方法:

@Override
public  void run() {
}

其他類似,

元注解

  • 負責注解其他注解
  • 包括(@Target,@Retention,@Documented,@Inherited),分別表示
    1. 描述注解使用范圍
    2. 需要上面級別保存該注釋資訊,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME,分別表示源代碼,編譯后的class檔案,運行時)
    3. 說明該注解將被包含在javadoc中
    4. 說明子類可以繼承父類中的該注解
//下面只能用到方法上,value的值可以取多個至于那些可以取CTRL+左鍵點擊ElementType類去看,另外可以省略value=
https://www.cnblogs.com/rainaftersummert/archive/2023/05/30/@Target(value = ElementType.METHOD)
//只能存在于原始碼上,值有那些同上,自己點進去看RetentionPolicy類,一般取RUNTIME
@Retention(value = RetentionPolicy.SOURCE)
//這兩個不多說
@Documented
@Inherited
//自定義注解
@interface MyAnnotation{

}

自定義注解

  • 使用@interface自定義注解,格式 public @interface 注解名{}
  • 其中每一個方法實際上是宣告了一個配置引數
  • 方法名稱就是引數名稱
  • 回傳值型別就是引數型別(回傳值只能是基本型別或class,String,enum)
  • 可以用default來宣告引數的默認值
  • 如果只有一個引數,一般引數名為value,只有一個引數時使用可以不寫引數名=
  • 注解元素必須有值,我們定義注解元素時,經常使用空字串,默認值為0
//元注解
@Retention(RetentionPolicy.RUNTIME)
@Inherited
//自定義注解
@interface MyAnnotation{
//    注解引數:引數型別+引數名(),可以設定默認值,沒默認值的話使用時必須傳參
    String name() default "";
    int a();
    int c() default 1;
}

//使用
@MyAnnotation(name = "lihua",a = 1)

反射(Reflection)

java是一個靜態語言(還有c,c++),因為它相對于動態語言來說,運行時結構不變,但是java可以利用反射來獲得類似動態語言的特性,成為“準動態語言”,

動態語言就是運行時可以改變其結構的語言,如:c#,js,php,python等

  • 反射機制運行程式在執行的程序中通過反射取得任何類的內部資訊,并且能夠直接操作任意物件的內部屬性及方法,

  • 主要API是Class

  • 反射是什么?

參考一下Class物件在java編譯運行的那個部分:

反射提供的部分功能:

  • 優點與缺點

    優點:動態編譯和創建,體現很大的靈活性

    缺點:對性能有影響

Class類

除了之前描述的,Class類還有一些特征:

  • Class 本身也是一個類
  • Class物件只能有系統建立物件
  • 一個加載的類在JVM中只會有一個Class實體
  • 一個Class物件對應的是一個加載到JVM中的一個.class檔案
  • 每個類的實體都會記得自己是由那個Class實體所生成的
  • 通過Class可以完整得到一個類中的所有被加載結構
  • Class類是反射的根源,,你要進行的任何針對類的動態加載運行等反射操作,都需要先得到該類的Class物件
public static void main(String[] args) throws ClassNotFoundException {
    /*1.下面是通過反射獲取Class物件的一種方式,引數是檔案路徑
      2.一個類在記憶體中只有一個Class類,在多創建幾個該類的Class
     也是同一個,
      3一個類被加載后,類的整個結構都會被封裝在Class物件中
      4.我們經常用的Object的getClass方法就是回傳一個Class物件,也是創建Class物件的一種常用方式
      5.反射在某種情況下可以理解為通過一個物件獲得類
     */
    Class<?> aClass = Class.forName("com.xxx.MyThread");
    System.out.println(aClass);
}

//out:class com.xxx.MyThread

Class類的常用方法:

Class類的四種創建方式

雖然上面可能已經描述過Class物件的創建方式的兩種,這里還是再來具體寫一下:

public class Test {

    public static void main(String[] args) throws ClassNotFoundException {
        Teacher teacher = new Teacher();
//        方式一:通過物件
        Class aClass = teacher.getClass();
        System.out.println(aClass);
//        方式二:forname
        Class<?> class1 = Class.forName("com.xxx.Teacher");
        System.out.println(class1);
//        比較兩者
        System.out.println(aClass==class1);
//        方式三:通過類名.class獲得
        Class<Teacher> teacherClass = Teacher.class;
        System.out.println(teacherClass);
//        比較
        System.out.println(teacherClass==class1);
//        方式四:基本資料型別的包裝類的type屬性
        Class<Integer> type = Integer.TYPE;
        System.out.println(type);
//        得到父類Class型別
        Class<?> superclass = class1.getSuperclass();
        System.out.println(superclass);
//     補充一下,獲得注解和void和Class本身的Class物件
        // Override.class
        // void.class
        //Class.class

    }
}

class Teacher extends  Person{}

/*
class com.xxx.Teacher
class com.xxx.Teacher
true
class com.xxx.Teacher
true
int
class com.xxx.Person

那些型別可以有Class物件?

包括以下:

注意:陣列長度即使不一致,只要型別和維度一樣,就是同一個Class

Class類的方法

獲得類完整結構
public class MyThread {
    private  int a;
    public  void run(String a){}

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public MyThread(int a) {
        this.a = a;
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
        Class c1 = Class.forName("com.xxx.MyThread");
        //獲取類名
        System.out.println(c1.getName());
        System.out.println(c1.getSimpleName());
//        獲得類屬性
        Field[] fields = c1.getFields();//只能找到public屬性
        fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }
//        獲得類方法
        System.out.println("-----------------------");
        Method[] methods = c1.getMethods();//包括繼承的方法
        methods=c1.getDeclaredMethods();//只包括本類的方法
        for (Method method : methods) {
            System.out.println(method);
        }
        System.out.println("-------------------------------");
//        獲得指定方法:沒s,兩個引數分別是方法名和方法引數型別的Class
        System.out.println(c1.getMethod("run",String.class));
//        獲得構造器
        System.out.println("----------------");
        Constructor[] constructors = c1.getConstructors();//獲得public構造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
//        同理getDeclaredConstructors()獲得的所有構造器,

        //獲得指定的構造器,引數為構造器引數的Class
        System.out.println("--------------------------");
        Constructor constructor = c1.getConstructor(int.class);
        System.out.println(constructor);
    }
}
/*out:

public void com.xxx.MyThread.run(java.lang.String)
public void com.xxx.MyThread.setA(int)
public int com.xxx.MyThread.getA()
-------------------------------
public void com.xxx.MyThread.run(java.lang.String)
----------------
public com.xxx.MyThread(int)
--------------------------
public com.xxx.MyThread(int)
操作類結構
public class MyThread {
    private  int a;
    public  void run(String a){
        System.out.println(a);
    }

    public int getA() {
        return a;
    }

    public MyThread() {
    }

    public void setA(int a) {
        this.a = a;
    }

    public MyThread(int a) {
        this.a = a;
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.xxx.MyThread");
//        構建一個物件:本質是呼叫無參構造器,其該類必須有無參構造器
//        MyThread myThread = (MyThread)aClass.newInstance();
//        通過構造器創建物件,可以用有參建構式
//       Constructor constructor= aClass.getDeclaredConstructor(int.class);
//       MyThread myThread1=(MyThread)constructor.newInstance(1);

//       通過反射呼叫方法
//        通過反射獲取一個方法
        MyThread myThread = (MyThread) aClass.newInstance();
        Method setName = aClass.getMethod("run", String.class);
//        invoke:激活,引數:物件名,方法引數
        setName.invoke(myThread,"helloworld");

//        通過反射操作屬性
        Field a=aClass.getDeclaredField("a");
//        取消安全檢查,否則無法操作私有屬性.method,field,consructor都有它,關閉也可以提高反射效率
        a.setAccessible(true);
        a.set(myThread,5);
        System.out.println(myThread.a);
    }
    
   /*out:
   helloworld
	5

類的加載程序

解釋一下符號參考和直接參考:

符號參考你可以理解為要參考的類目前在記憶體中還沒被加載出來,JVM當然不知道它在哪里,所以就用唯一的符號來表示就好像給它賦了一個變數,等到鏈接的時候類加載器決議地址完成變成直接參考

直接參考就是存盤參考類在真實記憶體中的地址

總而言之還是這張圖:

什么時候會發生類的初始化

主動參考比較好理解,下面只演示一下被動參考“

public class Main {
       //    初始化時執行一次靜態代碼塊
    static {
        System.out.println("main函式所在類被加載了");
    }
    public static void main(String[] args) throws ClassNotFoundException {
       System.out.println(son.sonAge);
       /*
       out:
       main函式所在類被加載了
       父類被加載了
       子類被加載了
       10
        */
//------------------------------------------------------
//        這就是第一條的意思
        System.out.println(son.fatherAge);
        /*
            out:
             main函式所在類被加載了
             父類被加載了
             23
         */
//--------------------------------------------------------
//      第二條:本質上只是開辟了一片空間
        son[] arr = new son[5];
        /*
        out:
        main函式所在類被加載了
         */
//--------------------------------------------------------
        //常量是不會引起初始化的
        System.out.println(son.M);
        /*
        out:
        main函式所在類被加載了
        1
         */
    }
}

class  father {
    static int fatherAge = 23;

    //    初始化時執行一次靜態代碼塊
    static {
        System.out.println("父類被加載了");
    }
}
class son extends father{
    static  int sonAge = 10;
    static  final  int M = 1;
    static {
        System.out.println("子類被加載了");
    }
}

類加載器

  • 類加載的作用:將class檔案位元組碼內容加載到記憶體中,并且將這些靜態資料轉換成方法區的運行時資料結構,然后在堆中生成一個代表這個類的java.lang.Class 物件,作為方法區中類資料的訪問入口,簡單來說,類加載器的作用就是把類(class)裝進記憶體
  • 類快取:標準的JavaSE類加載器可以按照要求查找類,但一旦某個類被加載到類加載器中,它將維持加載(快取)一段資料,不過JVM垃圾回識訓制可以回收這些Class物件

類加載器有那些?

java的主要jar包就是rt.jar,引導類加載器就是加載這一類核心jar包

 public static void main(String[] args) throws ClassNotFoundException {
//        獲取系統類的加載器
        ClassLoader classLoader = ClassLoader.getSystemClassLoader();
        System.out.println(classLoader);

//        獲取系統類加載器的父類加載器-->拓展加載器
        ClassLoader classLoader1 = classLoader.getParent();
        System.out.println(classLoader1);
//        獲得拓展類加載器的父類加載器-->根加載器(c/c++):這個java是無法獲得的
        ClassLoader classLoader2 = classLoader1.getParent();
        System.out.println(classLoader2);

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

//        測驗當前類是那個加載器加載的
        ClassLoader classLoader3 = Class.forName("com.xxx.MyThread").getClassLoader();
        System.out.println(classLoader3);
//        測驗jdk內部類是誰加載的:根加載器,輸出不出來
        ClassLoader classLoader4 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader4);

        //如何獲得系統類加載器可以加載的路徑
        System.out.println(System.getProperty("java.class.path"));

    }

/*out:
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
jdk.internal.loader.ClassLoaders$PlatformClassLoader@5594a1b5
null
------------------------
jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
null
本處按道理來說應該輸出所有jar包路徑,但是只說出了檔案根目錄,可能是因為jdk版本的原因,不確定,本處存疑

反射操作泛型

public class MyThread {
   public void test01(Map<String,MyThread> map, List<MyThread> list){
   }
   public  Map<String,Map> test02(){
       return  null;
   }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchFieldException {
       //獲得引數泛型
       Method method = MyThread.class.getMethod("test01", Map.class,List.class);
       //得到的是方法的引數Map,List
        Type[] genericExceptionTypes = method.getGenericParameterTypes();
        for (Type genericExceptionType : genericExceptionTypes) {
            if(genericExceptionType instanceof ParameterizedType){
                System.out.println(genericExceptionType);
                //得到的是方法引數的泛型
                Type[] actualTypeArguments = ((ParameterizedType) genericExceptionType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }
        }
        //獲得回傳值泛型
        Method method1 = MyThread.class.getMethod("test02");
        Type genericReturnType = method1.getGenericReturnType();
        if(genericReturnType instanceof  ParameterizedType){
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }
        }
    }

}

/*
java.util.Map<java.lang.String, com.xxx.MyThread>
class java.lang.String
class com.xxx.MyThread
java.util.List<com.xxx.MyThread>
class com.xxx.MyThread
class java.lang.String
interface java.util.Map

反射操作注解

ORM->物件關系映射

public class MyThread {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class<?> aClass = Class.forName("com.xxx.Teacher");
//        通過反射獲得注解
        Annotation[] annotations = aClass.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
//        獲得注解的value值
        Table table = (Table) aClass.getAnnotation(Table.class);
        String value = https://www.cnblogs.com/rainaftersummert/archive/2023/05/30/table.value();
        System.out.println(value);

//        獲得類指定注解
        Field f = aClass.getDeclaredField("id");
        Table annotation = f.getAnnotation(Table.class);
        System.out.println(annotation.value());


    }
}
@Table(value = "https://www.cnblogs.com/rainaftersummert/archive/2023/05/30/aaa")
class Teacher{
    @Table2(value = "https://www.cnblogs.com/rainaftersummert/archive/2023/05/30/aaa")
    private int id;
    @Override
    public String toString() {
        return super.toString();
    }
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Table{
    String value();
        }
//屬性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface Table2{
    String value();
}

/*
@com.xxx.Table(value="https://www.cnblogs.com/rainaftersummert/archive/2023/05/30/aaa")
aaa

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

標籤:其他

上一篇:Python連接es筆記三之es更新操作

下一篇:返回列表

標籤雲
其他(159992) Python(38189) JavaScript(25464) Java(18161) C(15234) 區塊鏈(8268) C#(7972) AI(7469) 爪哇(7425) MySQL(7217) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5344) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4579) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2434) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1977) 功能(1967) Web開發(1951) HtmlCss(1950) C++(1927) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1862) 谷歌表格(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
最新发布
  • java注解與反射

    # java注解與反射 - java注解與反射十分重要,是很多框架的底層 ## 注解(Annotataion) - 注解的作用: 1. 不是程式本身,可以對程式作出解釋 1. 可以被其他程式讀取 - 注解的格式:@注釋名,如@override表示重寫方法,而且有些還可以添加一些引數值,如@Suppr ......

    uj5u.com 2023-05-31 08:08:28 more
  • Python連接es筆記三之es更新操作

    > 本文首發于公眾號:Hunter后端 > 原文鏈接:[Python連接es筆記三之es更新操作](https://mp.weixin.qq.com/s/1cTaVfjLFrmbXajNcayhEA) 這一篇筆記介紹如何使用 Python 對資料進行更新操作。 對于 es 的更新的操作,不用到 Se ......

    uj5u.com 2023-05-31 08:03:03 more
  • 騰訊二面:有 40 億個 QQ 號,限制 1G 記憶體,問如何去重?被問懵了!

    > 40億個QQ號,限制1G記憶體,如何去重? 40億個unsigned int,如果直接用記憶體存盤的話,需要: `4*4000000000 /1024/1024/1024 = 14.9G` ,考慮到其中有一些重復的話,那1G的空間也基本上是不夠用的。 想要實作這個功能,可以借助位圖。 使用位圖的話, ......

    uj5u.com 2023-05-31 07:56:52 more
  • JavaWeb

    # JavaWeb ## 1、基本概念 ### 1.1、前言 web開發: - web,網頁的意思 - 靜態web - html,css - 提供給所有人看的資料始終不會發生變化 - 動態web - 幾乎所有的網站都是動態的 - 提供給所有人看的資料始侄訓發生變化,每個人在不同的時間,不同的地點看到 ......

    uj5u.com 2023-05-31 07:50:35 more
  • 新版idea快捷鍵總結學習----(用于java開發模式)

    ### 選擇代碼區 1. ctrl w - 如果放到以if開頭的陳述句,可以選擇if判斷條件所在的代碼片段 - 游標在單個單詞下時 選擇單詞 - 在選中多個單詞時,選擇整個字串 - 三次點擊時,如果不在字串單詞下,用于選擇{}內的代碼片段 逐級遞增 如果在單詞下方,用于選擇單詞所在的字串并且向外 ......

    uj5u.com 2023-05-31 07:50:18 more
  • geowebCache 切片不同方式的呼叫

    1.curl 方式 curl -v -u admin:geoserver -H "Content-type: application/json" -d "{'seedRequest':{'name':'NR:tdbp','bounds':{'coords':{ 'double':[ '108.790 ......

    uj5u.com 2023-05-31 07:50:09 more
  • np.bincount方法

    [官方檔案](https://numpy.org/doc/stable/reference/generated/numpy.bincount.html#numpy-bincount) `out = np.bincount(x[, weights, minlength])` **該函式用于統計輸入陣列 ......

    uj5u.com 2023-05-31 07:50:04 more
  • JavaWeb編程面試題——Spring Boot

    面試題==知識點,這里所記錄的面試題并不針對于面試者,而是將這些面試題作為技能知識點來看待。不以刷題進大廠為目的,而是以學習為目的。這里的知識點會持續更新,目錄也會隨時進行調整。 ......

    uj5u.com 2023-05-31 07:50:00 more
  • Python 實作 m3u8 視頻下載

    # Python 實作 m3u8 視頻下載 m3u8 是一種**基于文本的媒體播放串列檔案格式**,通常用于指定流媒體播放器播放在線媒體流。它是一個簡單的文本檔案,其中包含多個由 URI 參考的媒體資源檔案的 URL。m3u8 檔案通常包含多個 ts 檔案的鏈接,這些 ts 檔案是實際的視頻和音頻數 ......

    uj5u.com 2023-05-31 07:49:53 more
  • 一文詳解 Sa-Token 中的 SaSession 物件

    Sa-Token 是一個輕量級 java 權限認證框架,主要解決登錄認證、權限認證、單點登錄、OAuth2、微服務網關鑒權 等一系列權限相關問題。 > Gitee 開源地址:[https://gitee.com/dromara/sa-token](https://gitee.com/dromara/ ......

    uj5u.com 2023-05-31 07:49:45 more