主頁 > 後端開發 > 只用這一篇Java泛型的文章,保證你面試對答如流

只用這一篇Java泛型的文章,保證你面試對答如流

2021-02-27 10:34:24 後端開發

最近技術交流群里,有朋友問:Object和泛型T有啥區別,回答完問題,不禁在想,面試在即,還有那么多朋友不了泛型?是時候給大家整理一篇泛型相關的文章了,一篇文章全面搞定泛型,讓大家再也不愁面試或實踐中泛型相關的問題了,

什么是泛型

泛型是在JDK 5時就引入的新特性,也就是“引數化型別”,通俗來講就是將原來的具體型別通過引數化來定義,使用或呼叫時再傳入具體的型別(型別實參),

泛型的本質是為了引數化型別(在不創建新型別的前提下,通過泛型指定的不同型別來控制形參具體的型別),在泛型使用程序中,操作的資料型別被指定為一個引數,這種引數型別可以用在類、介面和方法中,分別被稱為泛型類、泛型介面、泛型方法,

為什么使用泛型

未使用泛型時,可以通過Object來實作引數的“任意化”,但這樣做的缺點就是需要顯式的強制型別轉換,這就需要開發者知道實際的型別,

而強制型別轉換是會出現錯誤的,比如Object將實際型別為String,強轉成Integer,編譯期是不會提示錯誤的,而在運行時就會拋出例外,很明顯的安全隱患,

Java通過引入泛型機制,將上述的隱患提前到編譯期進行檢查,開發人員既可明確的知道實際型別,又可以通過編譯期的檢查提示錯誤,從而提升代碼的安全性和健壯性,

使用泛型前后的對比

拿一個經典的例子來演示一下未使用泛型會出現的問題,

List list = new ArrayList();
list.add(1);
list.add("zhuan2quan");
list.add("程式新視界");

for (int i = 0; i < list.size(); i++) {
    String value = (String) list.get(i);
    System.out.println("value=" + value);
}

上述代碼在編譯器并不會報任何錯誤,但當執行時會拋出如下例外:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

那么,是否可以在編譯器就解決這個問題,而不是在運行期拋出例外呢?泛型應運而生,上述代碼通過泛型來寫之后,變成如下形式:

List<String> list = new ArrayList<>();
list.add(1);
list.add("zhuan2quan");
list.add("程式新視界");

for (String value : list) {
    System.out.println("value=" + value);
}

可以看出,代碼變得更加清爽簡單,而且list.add(1)這行代碼在IDE中直接會提示錯誤資訊:

Required type: String
Provided: int

提示錯誤資訊便是泛型對向List中添加的資料產生了約束,只能是String型別,

泛型中通配符

在使用泛型時經常會看到T、E、K、V這些通配符,它們代表著什么含義呢?

本質上它們都是通配符,并沒有什么區別,換成A-Z之間的任何字母都可以,不過在開發者之間倒是有些不成文的約定:

  • T (type) 表示具體的一個java型別;
  • K V (key value) 分別代表java鍵值中的Key Value;
  • E (element) 代表Element;

為什么Java的泛型是假泛型

為了做到向下兼容,Java中的泛型僅僅是一個語法糖,并不是C++那樣的真泛型,

還是上面的例子,在直接向泛型為String的List中添加int型別會提示錯誤:

List<String> list = new ArrayList<>();
list.add(1);

針對上述代碼,我們采用反射間接地呼叫add方法:

@Test
public void test3() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    List<Integer> list = new ArrayList<>();
    list.add(1);
    Method add = list.getClass().getMethod("add", Object.class);
    add.invoke(list,"程式新視界");
    System.out.println(list);
    System.out.println(list.get(1));
}

執行上述代碼,我們發現程式并沒有拋出例外,正常列印出入:

[1, 程式新視界]
程式新視界

原本只能裝入Integer的List,成功裝入了一個String型別的值,由此可見,所謂的泛型確實是假泛型,

同時,我們還可以通過位元組碼來證明,拿上面使用了泛型的實體代碼,通過javap -c命令來看看位元組碼:

Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #6                  // String zhuan2quan
      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: aload_1
      18: ldc           #7                  // String 程式新視界
      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      25: pop
      26: aload_1
      27: invokeinterface #18,  1           // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      32: astore_2
      33: aload_2
      34: invokeinterface #19,  1           // InterfaceMethod java/util/Iterator.hasNext:()Z
      39: ifeq          80

從位元組碼中可以看出,List.add方法本質上就是一個Object,再次證明,Java的泛型僅僅在編譯期有效,在運行期則會被擦除,也就是說所有的泛型引數型別在編譯后都會被清除掉,這就是我們經常說的型別擦除,

因此,也可以說:泛型型別在邏輯上看以看成是多個不同的型別,實際上都是相同的基本型別,

泛型的定義與使用

泛型有三類,分別為:泛型類、泛型介面、泛型方法,

在學習這三種型別的泛型使用場景之前,我們需要明確一個基本準則,那就是泛型的宣告通常都是通過<>配合大寫字母來定義的,比如<T>,只不過不同型別,宣告的位置不同,使用的方式也有所不同,

泛型類

泛型類的語法形式:

class name<T1, T2, ..., Tn> { /* ... */ }

泛型類的宣告和非泛型類的宣告類似,只是在類名后面添加了型別引數宣告部分,由尖括號(<>)分隔的型別引數部分跟在類名后面,它指定型別引數(也稱為型別變數)T1,T2,…和 Tn,一般將泛型中的類名稱為原型,而將<>指定的引數稱為型別引數,

使用示例:

// T為任意標識,比如用T、E、K、V等表示泛型
public class Foo<T> {

    // 泛化的成員變數,T的型別由外部指定
    private T info;

    // 構造方法型別為T,T的型別由外部指定
    public Foo(T info){
        this.info = info;
    }

    // 方法回傳值型別為T,T的型別由外部指定
    public T getInfo() {
        return info;
    }

    public static void main(String[] args) {
        // 實體化泛型類時,必須指定T的具體型別,這里為String,
        // 傳入的實參型別需與泛型的型別引數型別相同,這里為String,
        Foo<String> foo = new Foo<>("程式新視界");
        System.out.println(foo.getInfo());
    }
}

當然,上述示例中在使用泛型類時也可以不指定實際型別,語法上支持,那么此時與未定義泛型一樣,不推薦這種方式,

Foo foo11 = new Foo(1);

比如上述寫法,也是可行的,但時區了定義泛型的意義了,

泛型介面

泛型介面的宣告與泛型類一致,泛型介面語法形式:

public interface Context<T> {
    T getContext();
}

泛型介面有兩種實作方式:子類明確宣告泛型型別和子類不明確宣告泛型型別,

先看子類明確宣告泛型型別的示例:

// 實作泛型介面時已傳入實參型別,則所有使用泛型的地方都要替換成傳入的實參型別
public class TomcatContext implements Context<String> {
    @Override
    public String getContext() {
        return "Tomcat";
    }
}

子類不明確宣告泛型型別:

// 未傳入泛型實參時,與泛型類的定義相同,在宣告類的時候,需將泛型的宣告也一起加到類中
public class SpringContext<T> implements Context<T>{
    @Override
    public T getContext() {
        return null;
    }
}

當然,還有一種情況,就是我們把定義為泛型的類像前面講的一樣當做普通類使用,

上面的示例中泛型引數都是一個,當然也可以指定兩個或多個:

public interface GenericInterfaceSeveralTypes< T, R > {
    R performAction( final T action );
}

多個泛型引數可以用逗號(,)進行分割,

泛型方法

泛型類是在實體化類時指明泛型的具體型別;泛型方法是在呼叫方法時指明泛型的具體型別,泛型方法可以是普通方法、靜態方法、抽象方法、final修飾的方法以及構造方法,

泛型方法語法形式如下:

public <T> T func(T obj) {}

尖括號內為型別引數串列,位于方法回傳值T或void關鍵字之前,尖括號內定義的T,可以用在方法的任何地方,比如引數、方法內和回傳值,

protected abstract<T, R> R performAction( final T action );
 
static<T, R> R performActionOn( final Collection< T > action ) {
    final R result = ...;
    // Implementation here
    return result;
}

上述實體中可以看出泛型方法同樣可以定義多個泛型型別,

再看一個示例代碼:

public class GenericsMethodDemo1 {

    //1、public與回傳值中間<T>,宣告此方法的泛型型別,
    //2、只有宣告了<T>的方法才是泛型方法,泛型類中的使用了泛型的成員方法并不是泛型方法,
    //3、<T>表明該方法將使用泛型型別T,此時才可以在方法中使用泛型型別T,
    //4、T可以為任意標識,如T、E、K、V等,
    public static <T> T printClass(T obj) {
        System.out.println(obj);
        return obj;
    }

    public static void main(String[] args) {
        printClass("abc");
        printClass(123);
    }
}

需要注意的是,泛型方法與類是否是泛型無關,另外,靜態方法無法訪問類上定義的泛型;如果靜態方法操作的參考資料型別不確定的時候,必須要將泛型定義在方法上,

上述示例中如果GenericsMethodDemo1定義為GenericsMethodDemo1<T>,則printClass方法是無法直接使用到類上的T的,只能像上面代碼那樣訪問自身定義的T,

泛型方法與普通方法區別

下面,我們對比一下泛型方法和非泛型方法的區別:

// 方法一
public T getKey(){
    return key;
}

// 方法二
public <T> T showKeyName(T t){
    return t;
}

其中方法一雖然使用了T這個泛型宣告,但它用的是泛型類中定義的變數,因此這個方法并不是泛型方法,而像方法二中通過兩個尖括號宣告了T,這個才是真正的泛型方法,

對于方法二,還有一種情況,那就是類中也宣告了T,那么該方法引數的T指的只是此方法的T,而并不是類的T,

泛型方法與可變引數
@SafeVarargs
public final <T> void print(T... args){
	for(T t : args){
		System.out.println("t=" + t);
	}
}

public static void main(String[] args) {
	GenericDemo2 demo2 = new GenericDemo2();
	demo2.print("abc",123);
}

print方法列印出可變引數args中的結果,而且可變引數可以傳遞不同的具體型別,

列印結果:

t=abc
t=123

關于泛型方法總結一下就是:如果能使用泛型方法盡量使用泛型方法,這樣能將泛型所需到最需要的范圍內,如果使用泛型類,則整個類都進行了泛化處理,

泛型通配符

型別通配符一般是使用?代替具體的型別實參(此處是型別實參,而不是型別形參),當操作型別時不需要使用型別的具體功能時,只使用Object類中的功能,那么可以用?通配符來表未知型別,例如List<?>在邏輯上是List<String>、List<Integer>等所有List<具體型別實參>的父類,

/**
 * 在使用List<Number>作為形參的方法中,不能使用List<Ingeter>的實體傳入,
 * 也就是說不能把List<Integer>看作為List<Number>的子類;
 */
public static void getNumberData(List<Number> data) {
    System.out.println("data :" + data.get(0));
}

/**
 * 在使用List<String>作為形參的方法中,不能使用List<Number>的實體傳入;
 */
public static void getStringData(List<String> data) {
    System.out.println("data :" + data.get(0));
}

/**
 * 使用型別通配符可以表示同時是List<Integer>和List<Number>、List<String>的參考型別,
 * 型別通配符一般是使用?代替具體的型別實參,注意此處是型別實參;
 * 和Number、String、Integer一樣都是一種實際的型別,可以把?看成所有型別的父類,
 */
public static void getData(List<?> data) {
    System.out.println("data :" + data.get(0));
}

上述三個方法中,getNumberData只能傳遞List<Number>型別的引數,getStringData只能傳遞List<String>型別的引數,如果它們都只使用了Object類的功能,則可以通過getData方法的形式進行宣告,則同時支持各種型別,

上述這種型別的通配符也稱作無界通配符,有兩種應用場景:

  • 可以使用Object類中提供的功能來實作的方法,
  • 使用不依賴于型別引數的泛型類中的方法,

在getData中使用了?作為通配符,但在某些場景下,需要對泛型型別實參進行上下邊界的限制,如:型別實參只準傳入某種型別的父類或某種型別的子類,

上界通配符示例如下:

/**
 * 型別通配符上限通過形如List來定義,如此定義就是通配符泛型值接受Number及其下層子型別別,
 */
public static void getUperNumber(List<? extends Number> data) {
    System.out.println("data :" + data.get(0));
}

通過extends限制了通配符的上邊界,也就是只接受Number及其子型別別,介面的實作和類的集成都可以通過extends來表示,

而這里的Number也可以替換為T,表示該通配符所代表的型別是T型別的子類,

public static void getData(List<? extends T> data) {
    System.out.println("data :" + data.get(0));
}

與上界通配符示對照也有下界通配符:

public static void getData(List<? super Integer> data) {
    System.out.println("data :" + data.get(0));
}

下界通配符表示該通配符所代表的型別是T型別的父類,

泛型的限制

原始型別(比如:int,long,byte等)無法用于泛型,在使用的程序中需要通過它們的包裝類(比如:Integer, Long, Byte等)來替代,

final List< Long > longs = new ArrayList<>();
final Set< Integer > integers = new HashSet<>();

當然,在使用的程序中會涉及到自動拆箱和自動裝箱的操作:

final List< Long > longs = new ArrayList<>();
longs.add( 0L ); // 'long' 包裝為 'Long'
 
long value = longs.get( 0 ); // 'Long'解包'long'

泛型的型別推斷

當引入泛型之后,每處用到泛型的地方都需要開發人員加入對應的泛型型別,比如:

final Map<String, Collection<String>> map =
    new HashMap<String, Collection<String>>();
 
for(final Map.Entry< String, Collection<String> > entry: map.entrySet()) {
}

為了解決上述問題,在Java7中引入了運算子<>,編譯器可以推斷出該運算子所代表的原始型別,

因此,Java7及以后,泛型物件的創建變為如下形式:

final Map< String, Collection<String>> map = new HashMap<>();

小結

本篇文章帶大家從為什么使用泛型到如何在不同場景下使用泛型都進行了逐步的講解,通過本篇文章的學習,基本上可以應對使用和面試程序中90%以后上的場景,如果對你有所幫助,順手可以給個贊,

原文鏈接:《只用這一篇Java泛型的文章,保證你面試對答如流》

參考文章:

https://blog.csdn.net/s10461/article/details/53941091

https://www.cnblogs.com/jingmoxukong/p/12049160.html

https://blog.csdn.net/lxxiang1/article/details/81429987

https://www.javacodegeeks.com/2015/09/how-and-when-to-use-generics.html


程式新視界

公眾號“ 程式新視界”,一個讓你軟實力、硬技術同步提升的平臺,提供海量資料

微信公眾號:程式新視界

程式新視界 CSDN認證博客專家 Spring 架構 Java
個人公眾號【程式新視界】,一個硬技術,軟實力同步提升的平臺,《Spring Boo技術內幕:架構設計與實作原理》作者,《深入以太坊智能合約開發》聯合作者之一,主要從事于三方支付行業,

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

標籤:java

上一篇:多執行緒的執行緒安全與互斥解決方案——同步代碼塊/同步函式

下一篇:JavaWeb之會話技術

標籤雲
其他(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