主頁 > 後端開發 > Java的泛型

Java的泛型

2023-06-14 07:46:53 後端開發

泛型是我們需要的程式設計手段,使用泛型機制撰寫的程式代碼要比那些雜亂地使用 Object 變數,然后再進行強制型別轉換的代碼具有更好的安全性和可讀性,

至少在表面上看來,泛型很像 C++ 中的模板,與 Java —樣,在 C++ 中,模板也是最先被添加到語言中支持強型別集合的,但是,多年之后人們發現模板還有其他的用武之地,學習完本章的內容可以發現 Java 中的泛型在程式中也有新的用途,

為什么要使用泛型程式設計

泛型程式設計(Generic programming)意味著撰寫的代碼可以被很多不同型別的物件所重用,例如,我們并不希望為聚集 String 和 File 物件分別設計不同的類,實際上,也不需要這樣做,因為一個 ArrayList 類可以聚集任何型別的物件,這是一個泛型程式設計的實體,

實際上,在 Java 增加泛型類之前已經有一個 ArrayList 類,下面來研究泛型程式設計的機制是如何演變的,另外還會講解這對于用戶和實作者來說意味著什么,

型別引數的好處

在 Java 中增加范型類之前,泛型程式設計是用繼承實作的,實作時使用通用型別(如 Object 或 Comparable 介面),在使用時進行強制型別轉換,

泛型對于集合類尤其有用,ArrayList 就是一個無處不在的集合類,ArrayList 類維護一個 Object 型別的陣列(Object 類是所有類的父類):

// before generic classes
public class ArrayList {
    private Object[] elementData;
    // ...
    public Object get(int i) { ... }
    public void add(Object o) { ... }
}

這種方法有兩個問題,

  • 當獲取一個值時,必須進行強制型別轉換,
  • 此外,這里沒有錯誤檢査,可以向陣列串列中添加任何類的物件,對于 files.add(new File("..."); 這個呼叫,編譯和運行都不會出錯,然而在其他地方,如果將 get() 的結果強制型別轉換為 String 型別, 就會產生一個錯誤,
ArrayList files = new ArrayList();
String filename = (String) files.get(0);

泛型提供了一個更好的解決方案:型別引數(type parameters),ArrayList 類有一個型別引數用來指示元素的型別:ArrayList<String> files = new ArrayList<String>();這使得代碼具有更好的可讀性,人們一看就知道這個陣列串列中包含的是 String 物件,

在 Java7 及以后的版本中,建構式中可以省略泛型型別:ArrayList<String> files = new ArrayList<>();省略的型別可以從變數的型別推斷得出,

編譯器也可以很好地利用這個資訊,當呼叫 get() 方法的時候,不需要進行強制型別轉換,編譯器就知道回傳值型別為 String,而不是 Object:String filename = files.get(0);

編譯器還知道 ArrayList 中 add() 方法有一個型別為 String 的引數,現在, 編譯器可以進行檢査,避免插入錯誤型別的物件,例如下面的代碼是無法通過編譯的,這將比使用 Object 型別的引數安全一些,出現編譯錯誤比類在運行時出現類的強制型別轉換例外要好得多,

files,add(new File("...")); // can only add String objects to an ArrayList<String>

型別引數的魅力在于:使得程式具有更好的可讀性和安全性,

誰想成為泛型程式員

使用像 ArrayList 這樣的泛型類很容易,大多數 Java 程式員都使用 ArrayList 這樣的型別,就好像它們已經構建在語言之中,像 String[] 陣列一樣,(當然, 陣列串列比陣列要好一些,因為陣列串列可以自動擴容,)

但是,實作一個泛型類并沒有那么容易,對于型別引數,使用這段代碼的程式員可能想要內置(plugin)所有的類,他們希望在沒有過多的限制以及混亂的錯誤訊息的狀態下,做所有的事情,因此,一個泛型程式員的任務就是預測出所用類的未來可能有的所有用途,

這一任務難到什么程度呢?下面是標準類別庫的設計者們肯定產生爭議的一個典型問題,ArrayList 類的 addAll() 方法用來添加另一個集合的全部元素,程式員可能想要將 ArrayList 中的所有元素添加到 ArrayList 中去(Manager 類是 Employee 類的子類),然而,反過來就不行了,如何設計才能只允許前一個呼叫,而不允許后一個呼叫呢?Java 語言的設計者發明了一個具有獨創性的新概念,通配符型別(wildcard type),它解決了這個問題,通配符型別非常抽象,然而,它們能讓庫的構建者撰寫出盡可能靈活的方法,


泛型程式設計劃分為 3 個能力級別,基本級別是,僅僅使用泛型類:典型的是像 ArrayList 這樣的集合,不必考慮它們的作業方式與原因,大多數應用程式員將會停留在這一級別上,直到出現了什么問題,當把不同的泛型類混合在一起時,或是在與對型別引數一無所知的遺留的代碼進行銜接時,可能會看到含混不清的錯誤訊息,如果這樣的話,就需要系統地學習 Java 泛型來解決這些問題,而不要胡亂地猜測,當然,最終可能想要實作自己的泛型類與泛型方法,

應用程式員很可能不喜歡撰寫太多的泛型代碼,JDK 開發人員已經做出了很大的努力,為所有的集合類提供了型別引數,憑經驗來說,那些原本涉及許多來自通用型別(如 Object 或 Comparable 介面)的強制型別轉換的代碼一定會因使用型別引數而受益,

本章介紹實作自己的泛型代碼需要了解的各種知識,希望大多數讀者可以利用這些知識解決一些疑難問題,并滿足對于引數化集合類的內部作業方式的好奇心,

泛型類

泛型類(generic class)就是具有一個或多個型別引數的類,

本章使用一個簡單的 Pair 類作為例子,

public class Pair<T> {
    private T first;
    private T second;
    
    public Pair() { first = null ; second = null ; }
    public Pair(T first, T second) { this.first = first; this.second = second; }
    
    public T getFirst() { return first; }
    public T getSecond() { return second; }
    
    public void setFirst(T newValue) { first = newValue; }
    public void setSecond(T newValue) { second = newValue; }
}

Pair 類引入了一個型別引數 T,用尖括號(< >)括起來,并放在類名的后面,

泛型類可以有多個型別引數,如果有多個型別變數,多個型別變數之間用 “,”逗號分隔,例如,可以定義 Pair 類,其中第一個域和第二個域使用不同的型別:public class Pair<T, U> { ... }

類定義中的型別引數指定方法的回傳型別以及域和區域變數的型別,例如,private T first;


用具體的型別替換型別引數就可以實體化泛型型別,例如:Pair 可以將結果想象成帶有構造器的普通類:

  • Pair()
  • Pair(String, String)

和方法:

  • String getFirst()、String getSecond()
  • void setFirst(String)、void setSecond(String)

換句話說,泛型類可看作普通類的工廠,

泛型方法

前面已經介紹了如何定義一個泛型類,實際上,還可以定義一個帶有型別引數的簡單方法,

class ArrayAlg {
    public static <T> T getMiddle(T... a) {
        return a[a.length / 2];
    }
}

這個方法是在普通類中定義的,而不是在泛型類中定義的,然而,這是一個泛型方法,可以從尖括號和型別引數看出這一點,注意,型別引數放在修飾符(這里是 public static)的后面,回傳型別的前面,


泛型方法可以定義在普通類中,也可以定義在泛型類中,

當呼叫一個泛型方法時,在方法名前的尖括號中放入具體的型別:

String middle = ArrayAlg.<String>getMiddle("]ohn", "Q.", "Public");

在這種情況(實際也是大多數情況)下,方法呼叫中可以省略 型別引數,編譯器有足夠的資訊能夠推斷出所呼叫的方法,它用 names 的型別(即 String[])與泛型型別 T[] 進行匹配并推斷出 T 一定是 String,也就是說,可以呼叫

String middle = ArrayAlg.getMiddle("]ohn", "Q.", "Public");

型別引數的限定

有時,類或方法需要對型別引數加以約束,下面是一個典型的例子,我們要計算陣列中的最小元素:

class ArrayAIg {
    // almost correct
    public static <T> T min(T[] a) {
        if (a == null || a.length == 0) {
            return null;
        }
        T smallest = a[0];
        for (int i = 1; i < a.length; i++) {
            if (smallest.compareTo(a[i]) > 0) smallest = a[i];
        }
        return smallest;
    }
}

但是,這里有一個問題,請看一下 min() 方法的代碼內部,變數 smallest 型別為 T,這意味著它可以是任何一個類的物件,怎么才能確信 T 所屬的類有 compareTo() 方法呢?

解決這個問題的方案是將 T 限制為實作了 Comparable 介面(只含一個 compareTo() 方法的標準介面)的類,可以通過對型別引數 T 設定限定(bound)實作這一點:

public static <T extends Comparable> T min(T[] a) {}

現在,泛型的 min() 方法只能被實作了 Comparable 介面的類(如 String、LocalDate 等)的陣列呼叫,

T extends 系結型別表示 T 應該是系結型別的子型別(subtype),T 和系結型別可以是類,也可以是介面,


一個型別引數或通配符可以有多個限定,多個限定之間用 “ &” 分隔,例如:T extends Comparable & Serializable,在Java的限定中,可以根據需要擁有多個介面限定,但至多有一個類限定,如果用一個類作為限定,它必須放在限定串列中的第一個位置,

// ok
T extends Object & Comparable & Serializable
// error
T extends Comparable & Serializable & Object

泛型代碼和虛擬機

型別擦除

型別擦除是Java泛型實作的一種方式,

型別擦除指的是:在編譯時,將泛型型別擦除成其原始型別,

虛擬機沒有泛型型別物件,所有物件都屬于普通類,無論何時定義一個泛型型別,都自動提供了一個相應的原始型別(raw type),型別引數用第一個限定的型別來替換,如果沒有給定限定就用 Object 替換,例如:

  • 類 Pair 中的型別引數沒有顯式的限定,因此,原始型別用 Object 替換 T,
  • 類 Interval<T extends Comparable & Serializable> 中第一個限定的型別為 Comparable,因此,原始型別用 Comparable 替換 T,

Pair 的原始型別如下所示,結果是一個普通的類,就好像泛型引入 Java 語言之前已經實作的那樣,在程式中可以包含不同型別的 Pair,例如,Pair 或 Pair,而擦除型別后就變成原始的 Pair 型別了,

public class Pair {
    private Object first;
    private Object second;
    
    public Pair(Object first, Object second) {
        this.first = first;
        this.second = second;
    }
    
    public Object getFirst() { return first; }
    public Object getSecond() { return second; }
    
    public void setFirst(Object newValue) { first = newValue; }
    public void setSecond(Object newValue) { second = newValue; }
}

翻譯泛型運算式

當程式呼叫泛型方法時,如果擦除回傳型別,編譯器插入強制型別轉換,例如,下面這個陳述句序列:

Pair<Employee> buddies = ...;
Employee buddy = buddies.getFirst();

擦除 getFirst() 方法的回傳型別后,getFirst() 方法將回傳 Object 型別,編譯器自動插入 Employee 的強制型別轉換,也就是說,編譯器把這個方法呼叫翻譯為兩條虛擬機指令:

  • 對 Pair#getFirst() 原始方法的呼叫,
  • 將回傳的 Object 型別強制轉換為 Employee 型別,

當存取一個泛型域時也要插入強制型別轉換,假設 Pair 類的 first 域和 second 域都是公有的,運算式:Employee buddy = buddies.first;也會在結果位元組碼中插入強制型別轉換,

翻譯泛型方法

型別擦除也會出現在泛型方法中,程式員通常認為下述的泛型方法 public static <T extends Comparable> T min(T[] a)是一個完整的方法族,而擦除型別之后,只剩下一個方法:public static Comparable min(Comparable[] a)

注意,型別引數 T 已經被擦除了,只留下了限定型別 Comparable,


型別擦除帶來了兩個復雜問題,看一看下面這個示例:

class DateInterval extends Pair<LocalDate> {
    public void setSecond(LocalDate second) {
        if (second.compareTo(getFirst()) >= 0) {
            super.setSecond(second);
        }
    }
    ...
}

一個日期區間是一對 LocalDate 物件,并且需要覆寫這個方法來確保第二個值永遠不小于第一個值,這個類擦除后變成

// after erasure
class DateInterval extends Pair {
    public void setSecond(LocalDate second) { ... }
    ...
}

令人感到奇怪的是,存在另一個從 Pair 繼承的 setSecond() 方法,即 public void setSecond(Object second)這顯然是一個不同的方法,因為它有一個不同型別的引數 Object,而不是 LocalDate,然而,不應該不一樣,考慮下面的陳述句序列:

DateInterval interval = new DateInterval(...);
Pair<LocalDate> pair = interval; // OK assignment to superclass
pair.setSecond(aDate);

這里,希望對 setSecond() 的呼叫具有多型性,并呼叫最合適的那個方法,由于 pair 參考 Datelnterval 物件,所以應該呼叫 Datelnterval.setSecond(),問題在于型別擦除與多型發生了沖突,要解決這個問題,就需要編譯器在 Datelnterval 類中生成一個橋方法(bridge method):

public void setSecond(Object second) { setSecond((Date) second); }

有關泛型的事實

需要記住有關 Java 泛型轉換的事實:

  • 虛擬機中沒有泛型,只有普通的類和方法,
  • 所有的型別引數都用它們的限定型別替換,
  • 橋方法被合成來保持多型,
  • 為保持型別安全性,必要時插入強制型別轉換,

類 A 是類 B 的子類,但是 G 和 G 不具有繼承關系,二者是并列關系,

public static void printBuddies(Pair<Employee> p) { ... }

// Manager 類是 Employee 類的子類
Pair<Manager> pair = new Pair<>();
// error(固定的泛型型別系統的局限,通配符型別解決了這個問題)
printBuddies(pair);

泛型一般有三種使用方式:泛型類、泛型方法、泛型介面,

// 泛型類
public class Pair<T>
// 實體化泛型類
Pair<String> pair = new Pair<>();
// 繼承泛型類,指定型別
class DateInterval extends Pair<LocalDate>

// 泛型方法
public static <T> T getMiddle(T... a)

// 泛型介面
public interface Generator<T>
// 實作泛型介面,指定型別
class GeneratorImpl implements Generator<String>

通配符型別

固定的泛型型別系統使用起來并沒有那么令人愉快,型別系統的研究人員知道這一點已經有一段時間了,Java 的設計者發明了一種巧妙的(仍然是安全的)“解決方案”:通配符型別,下面幾小節會介紹如何處理通配符,

通配符概念

通配符型別中,允許型別引數變化,例如,通配符型別 Pair<? extends Employee> 表示任何泛型 Pair 型別,它的型別引數是 Employee 的子類,如 Pair,但不是 Pair

假設要撰寫一個列印雇員對的方法,像這樣:

public static void printBuddies(Pair<Employee> p) {
    Employee first = p.getFirst();
    Employee second = p.getSecond();
    System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
}

正如前面講到的,不能將 Pair 傳遞給這個方法,這一點很受限制,解決的方法很簡單:使用通配符型別:

public static void printBuddies(Pair<? extends Employee> p)

型別 Pair 是 Pair<? extends Employee> 的子型別(如圖 8-3 所示),

image-20230409215348891.png


使用通配符會通過 Pair<? extends Employee> 的參考破壞 Pair 嗎?

Pair<Manager> managerBuddies = new Pair<>(ceo, cfo);
Pair<? extends Employee> wildcardBuddies = managerBuddies; // OK
wildcardBuddies.setFirst(lowlyEmployee); // compile-time error

這可能不會引起破壞,對 setFirst() 的呼叫有一個型別錯誤,要了解其中的緣由,請仔細看一看型別 Pair<? extends Employee>,其方法似乎是這樣的:

? extends Employee getFirst()
void setFirst(? extends Employee)

這樣將不可能呼叫 setFirst() 方法,編譯器只知道需要某個 Employee 的子型別,但不知道具體是什么型別,它拒絕傳遞任何特定的型別,畢竟 ? 不能用來匹配,

使用 getFirst() 就不存在這個問題:將 getFirst() 的回傳值賦給一個 Employee 的參考完全合法,這就是引入有限定的通配符的關鍵之處,現在已經有辦法區分安全的訪問器方法和不安全的更改器方法了,

通配符的超型別限定

通配符限定與型別引數限定十分類似,但是,通配符限定還有一個附加的能力,即可以指定一個超型別限定(supertype bound),如下所示:? super Manager,

這個通配符限制為 Manager 的所有超型別,(已有的 super 關鍵字十分準確地描述了這種聯系)

參考資料

《Java核心技術卷一:基礎知識》(第10版)第 8 章:泛型程式設計

本文來自博客園,作者:真正的飛魚,轉載請注明原文鏈接:https://www.cnblogs.com/feiyu2/p/17476544.html

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

標籤:Java

上一篇:【解決一個小問題】golang 的 `-race`選項導致 unsafe代碼 panic

下一篇:返回列表

標籤雲
其他(160896) Python(38222) JavaScript(25493) Java(18226) C(15237) 區塊鏈(8270) C#(7972) AI(7469) 爪哇(7425) MySQL(7248) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5874) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4591) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2435) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1964) Web開發(1951) C++(1939) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(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的泛型

    泛型程式設計(Generic programming) 意味著撰寫的代碼可以被很多不同型別的物件所重用。泛型對于集合類尤其有用,例如,ArrayList 就是一個無處不在的集合類。一個 ArrayList 類可以聚集任何型別的物件,這是一個泛型程式設計的實體。 ......

    uj5u.com 2023-06-14 07:46:53 more
  • 【解決一個小問題】golang 的 `-race`選項導致 unsafe代碼 panic

    **作者:張富春(ahfuzhang),轉載時請注明作者和參考鏈接,謝謝!** * [cnblogs博客](https://www.cnblogs.com/ahfuzhang/) * [zhihu](https://www.zhihu.com/people/ahfuzhang/posts) * [G ......

    uj5u.com 2023-06-14 07:46:34 more
  • Go 語言之 sqlx 庫使用

    # Go 語言之 sqlx 庫使用 ## 一、sqlx 庫安裝與連接 ### sqlx 介紹 sqlx is a library which provides a set of extensions on go's standard `database/sql` library. The sqlx ......

    uj5u.com 2023-06-14 07:46:24 more
  • 深入探究for...range陳述句

    # 1. 引言 在Go語言中,我們經常需要對資料集合進行遍歷操作。對于陣列來說,使用for陳述句可以很方便地完成遍歷。然而,當我們面對其他資料型別,如map、string 和 channel 時,使用普通的for回圈無法直接完成遍歷。為了更加便捷地遍歷這些資料型別,Go語言引入了for...range ......

    uj5u.com 2023-06-14 07:46:18 more
  • vs2022 wxWidgets

    # 下載 https://www.wxwidgets.org/downloads/ 下載壓縮包即可 ![image](https://img2023.cnblogs.com/blog/916065/202306/916065-20230614040303993-2082032985.png) # 編 ......

    uj5u.com 2023-06-14 07:45:22 more
  • OpenFoam——自定義求解器

    ## 1、求解器 ### 1.1 復制原始碼 本案例以icoFoam為例,復制【openFOAM/OpenFOAM-9/applications/solvers/incompressible/icoFoam】檔案夾至run檔案夾下(我的是【openFOAM/mtl-9/run/solvers/inco ......

    uj5u.com 2023-06-14 07:44:36 more
  • C++面試八股文:什么是RAII?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第13面: > 面試官:什么是`RAII`? > > 二師兄:`RAII`是`Resource Acquisition Is Initialization`的縮寫。翻譯成中文是資源獲取即初始化。 > > 面試官:`RAII`有什么特點和優勢? > > ......

    uj5u.com 2023-06-14 07:44:13 more
  • 現代C++學習指南-方向篇

    C++是一門有著四十年歷史的語言,先后經歷過四次版本大升級(誕生、98、11、17(20),14算小升級)。每次升級都是很多問題和解決方案的取舍。了解這些歷史,能更好地幫助我們理清語言的發展脈絡。所以接下來我將借它的發展歷程,談一談我對它的理解,最后給出我認為比較合理的學習路線指南。 ### C++ ......

    uj5u.com 2023-06-14 07:44:09 more
  • 現代C++學習指南-型別系統

    > 在前一篇,我們提供了一個方向性的指南,但是學什么,怎么學卻沒有詳細展開。本篇將在前文的基礎上,著重介紹下怎樣學習C++的型別系統。 ### 寫在前面 在進入型別系統之前,我們應該先達成一項共識——盡可能使用C++的現代語法。眾所周知,出于兼容性的考慮,C++中很多語法都是合法的。但是隨著新版本的 ......

    uj5u.com 2023-06-14 07:44:04 more
  • 主席樹學習筆記

    # 什么是主席樹 主席樹這個名字看上去很高級,其實不然,它還有另一個名字——可持久化線段樹。 ## 什么是可持久化 可持久化顧名思義就是它可以變得~~**持久**~~,就是我們對他不斷進行單點修改后,突然查詢它的某一個歷史版本,這就叫可持久化。 # 引入例題 [洛谷3919:可持久化陣列](http ......

    uj5u.com 2023-06-14 07:43:57 more