初識Java 18-3 泛型

目錄

邊界

通配符

編譯器的能力范疇

逆變性

無界通配符

捕獲轉換


本筆記參考自: 《On Java 中文版》


邊界

??????? 在泛型中,邊界的作用是:在參數類型上增加限制。這么做可以強制執行應用泛型的類型規則,但還有一個更重要的潛在效果,我們可以調用邊界類型上的方法了。

??? 若一個泛型參數沒有邊界,那么我們只能調用其中的Object方法。

??????? 為了應用邊界的限制,Java復用了extend關鍵字:

【例子:使用extend規定泛型邊界】

interface HasColor {java.awt.Color getColor();
}class WithColor<T extends HasColor> {T item;WithColor(T item) {this.item = item;}T getItem() {return item;}// 可以調用位于邊界上的方法:java.awt.Color color() {return item.getColor();}
}class Coord {public int x, y, z;
}// 在規定邊界時,需要將類排(Coord)在前面,接口(HasColor)排在后面\
// 因此這種寫法會失敗:
// class WithColorCoord<T extends HasColor & Coord> {}// 這樣才能正確定義多重邊界:
class WithColorCoord<T extends Coord & HasColor> {T item;WithColorCoord(T item) {this.item = item;}T getItem() {return item;}java.awt.Color color() {return item.getColor();}int getX() {return item.x;}int getY() {return item.y;}int getZ() {return item.z;}
}interface Weight {int weight();
}// 與繼承一樣,只能繼承一個具體類,但可以實現多個接口:
class Solid<T extends Coord & HasColor & Weight> {T item;Solid(T item) {this.item = item;}T getItem() {return item;}java.awt.Color color() {return item.getColor();}int getX() {return item.x;}int getY() {return item.y;}int getZ() {return item.z;}int weight() {return item.weight();}
}class Bounded extends Coord implements HasColor, Weight {@Overridepublic java.awt.Color getColor() {return null;}@Overridepublic int weight() {return 0;}
}public class BasicBounds {public static void main(String[] args) {Solid<Bounded> solid =new Solid<>(new Bounded());solid.color();solid.getY();solid.weight();}
}

??????? 可以通過繼承去除上例中的一些冗余代碼。繼承也可以增加邊界的限制:

【例子:使用繼承簡化代碼】

class HoldItem<T> {T item;HoldItem(T item) {this.item = item;}T getItem() {return item;}
}class WithColor2<T extends HasColor>extends HoldItem<T> {WithColor2(T item) {super(item);}java.awt.Color color() {return item.getColor();}
}class WithColorCoord2<T extends Coord & HasColor>extends WithColor2<T> {WithColorCoord2(T item) {super(item);}int getX() {return item.x;}int getY() {return item.y;}int getZ() {return item.z;}
}class Solid2<T extends Coord & HasColor & Weight>extends WithColorCoord2<T> {Solid2(T item) {super(item);}int weight() {return item.weight();}
}public class InheritBounds {public static void main(String[] args) {Solid2<Bounded> solid2 =new Solid2<>(new Bounded());solid2.color();solid2.getY();solid2.weight();}
}

??????? Solid2變得更加簡潔了。

????????在這里,每一層的繼承都會為對應的類增加邊界的限制,同時繼承那些來自父類的方法。這樣我們就不需要在每個類中重復定義那些代碼了。

??????? 另外,創建泛型集合時需要注意,我們可以且只可以繼承一個接口或類:

// 可以進行的操作:
List<? extends Coord> list;
List<? extends HasColor> list1;
// 不可行的操作:
// List < ? extends HasColor & Weight > list2;

通配符

??????? 先看一個例子,將派生類的數組賦值給基類數組的引用:

【例子:數組的特殊行為】

class Fruit {
}class Apple extends Fruit {
}class Jonathan extends Apple {
}class Orange extends Fruit {
}public class CovariantArrays {public static void main(String[] args) {Fruit[] fruit = new Apple[10];// 可行的操作:fruit[0] = new Apple();fruit[1] = new Jonathan();// 但運行時的類型是Apple[],而不是Fruit[]或Orange[]try {// 編譯器允許添加Fruit(父類):fruit[0] = new Fruit();} catch (Exception e) { // 但這種操作卻會導致ArrayStoreException異常System.out.println(e);}try {// 編譯器允許添加Orange:fruit[0] = new Orange();} catch (Exception e) { // 但同樣會發生異常System.out.println(e);}}
}

??????? 程序執行的結果是:

??????? 在這個例子中,我們將派生類Apple的數組賦值給了Fruit數組:

Fruit[] fruit = new Apple[10];

這在繼承結構上是合理的。

??????? 不過需要注意一點,因為實際的數組類型是Apple[],所以將基類Fruit放入其中是不合理的編譯器允許了這個行為,因為從代碼上看,這只不過是將Fruit對象賦給了Fruit數組。數組機制能夠知道數組的實際類型,因此才會在運行時拋出異常。

??? 數組可以維持其包含的對象的類型規則,這也是為什么上例這種類似“向上轉型”的操作能夠成功的原因。它在一定程度上能夠確保我們不會亂用數組。

??????? 盡管我們能夠在運行時發現這種不合理的數組賦值。但使用泛型,我們可以在編譯時提前進行錯誤檢測:

【例子:泛型的編譯時檢查】

import java.util.ArrayList;
import java.util.List;public class NonCovariantGenerics {List<Fruit> flist = new ArrayList<Apple>();
}

??????? 編譯器會在編譯時發現如下的問題:

它告訴我們,我們無法將包含Apple的泛型賦值給包含Fruit的泛型。

??????? 之所以會這樣,是因為編譯器無法掌握足夠的信息,它并不知道List<Fruit>List<Apple>是什么關系(另外,這種關系也不會涉及向上轉型,二者并不等價)。

??????? 可以發現,在這里我們需要討論的是集合自身的類型,而不是集合持有的元素類型。

??? 與數組不同,泛型并沒有內建的協變性。數組完全由語言自身定義,而泛型的定義卻來自于程序員。因此,編譯器和運行系統有足夠的信息來檢查數組,卻無法對泛型做到相同的事。

??????? 若一定需要在List<Fruit>List<Apple>之間建立什么關系,可以使用通配符:

【例子:使用通配符建立關系】

import java.util.ArrayList;
import java.util.List;public class NonCovariantGenerics {public static void main(String[] args) {// 可以用通配符提供協變的能力:List<? extends Fruit> flist = new ArrayList<>();// 但卻不能添加任何類型的數據// flist.add(new Apple());// flist.add(new Fruit());// flist.add(new Object());flist.add(null); // 可以添加null,但沒什么用// 至少能返回一個Fruit對象:Fruit f = flist.get(0);}
}

??????? 顯然,這并不意味著flist真的會持有任何Fruit類型,因為<? extends Fruit>實際上表示的是“某種繼承自Fruit的類型”。這里存在著一個矛盾:

集合應該持有具體的類型,但flist只要求提供一種沒有被確切指定的類型。

換言之,flist所要求的類型并不具體(這是為了能夠向上轉型為flist做出的犧牲)

??? 若一個集合并不要求所持有的類型足夠具體,這個集合就會失去意義。而若我們并不知道集合持有的具體元素是什么,我們也無法安全地向其中添加元素。

??????? 因為這種限制,通配符并不適合用于傳入參數的集合。但我們可以將其用于接收一個已經打包好的集合,并從中取出元素。

編譯器的能力范疇

??????? 按照上面的說法,若使用了通配符,我們似乎無法調用一個帶有參數的集合方法了。先看看這個例子:

【例子:調用泛型集合中的含參方法】

import java.util.Arrays;
import java.util.List;public class CompilerIntelligence {public static void main(String[] args) {List<? extends Fruit> flist =Arrays.asList(new Apple());Apple a = (Apple) flist.get(0); // 未產生警告// 方法中的參數是Object:flist.contains(new Apple());// 同樣,參數也是Object:flist.indexOf(new Apple());}
}

??????? 程序能夠順利執行。這似乎與之前得出的結論相悖——我們可以調用含參的集合方法。這是否是編譯器在其中進行調度呢?

??????? 答案是否定的,可以觀察contains()indexOf()方法的參數列表:

contains()indexOf()的參數都是Object的,假若我們調用了flist.add()方法,則會發現:

因為此時add()方法是參數已經變成了? extends Fruit。編譯器不會知道應該處理哪種具體的Fruit類型,因此不會接受任何類型。

??????? 這里體現了一種思路:作為泛型類的設計者,若我們認為某種調度是“安全的”,那么可以將Object作為其的參數。例如:

【例子:設置“安全”調度的參數】

import java.util.Objects;public class Holder<T> {private T value;public Holder() {}public Holder(T val) {value = val;}public void set(T val) {value = val;}public T get() {return value;}// 使用Object作為參數@Overridepublic boolean equals(Object o) {return o instanceof Holder &&Objects.equals(value, ((Holder) o).value);}@Overridepublic int hashCode() {return Objects.hashCode(value);}public static void main(String[] args) {Holder<Apple> apple = new Holder<>(new Apple());Apple d = apple.get();apple.set(d);// 不允許這種操作:// Holder<Fruit> fruit = apple;// 但允許這種操作:Holder<? extends Fruit> fruit = apple;Fruit p = fruit.get();d = (Apple) fruit.get(); // 返回一個Object,然后再轉型try {Orange c = (Orange) fruit.get();} catch (Exception e) {System.out.println(e);}// 無法這樣調用set():// fruit.set(new Apple());// fruit.set(new Fruit());System.out.println(fruit.equals(d));}
}

??????? 程序執行的結果是:

??????? 可以看到,Holder<Apple>無法向上轉型為Holder<Fruit>,但卻可以向上轉型為Holder<? extends Fruit>get()方法和set()方法的使用都會受編譯器的限制,值得一提的是,因為get()方法返回了Fruit,所以我們可以手動進行向下轉型。

??????? 因為equals()方法接受Object,所以它不會受到上述的限制。


逆變性

??????? 除extends之外,還可以使用超類通配符(重寫了super關鍵字)。如果說extends關鍵字可以為泛型添加限制,那么super就是為通配符添加了邊界限制,其中的邊界限制就是某個類的基類。例如:

<? super MyClass>
<? super T> // 可以使用類型參數
// <T super MyClass> // 但無法為泛型參數設置超類邊界

??????? 有了超類通配符,就可以向集合中進行寫操作了:

【例子:向泛型集合中進行寫操作】

import java.util.List;public class SuperTypeWildcards {static void writeTo(List<? super Apple> apples) {apples.add(new Apple());apples.add(new Jonathan());// 但不可以添加基類元素:// apples.add(new Fruit());}
}

??????? 我們可以向apples類型中添加Apple及其的子類型。但由于apples的下界是Apple,所以我們無法安全地先這個泛型集合中添加Fruit

【例子:總結一下通配符】

import java.util.Arrays;
import java.util.List;public class GenericReading {static List<Apple> apples =Arrays.asList(new Apple());static List<Fruit> fruit =Arrays.asList(new Fruit());// 調用精確的類型:static <T> T readExact(List<T> list) {return list.get(0);}// 兼容各種調用的靜態方法:static void f1() {Apple a = readExact(apples);Fruit f = readExact(fruit);f = readExact(apples);}// 類的類型會在其實例化后確定:static class Reader<T> {T readExact(List<T> list) {return list.get(0);}}static void f2() {Reader<Fruit> fruitReader = new Reader<>();Fruit f = fruitReader.readExact(fruit);// fruitReader的參數類型是Fruit// 因此不會接受List<Apple>:// Fruit a = fruitReader.readExact(apples);}// 允許協變:static class CovariantReader<T> {T readCovariant(List<? extends T> list) {return list.get(0);}}static void f3() {CovariantReader<Fruit> fruitReader =new CovariantReader<>();Fruit f = fruitReader.readCovariant(fruit);Fruit a = fruitReader.readCovariant(apples);}public static void main(String[] args) {f1();f2();f3();}
}

??????? f1()使用了一個靜態的泛型方法readExact()。從f1()中的調用可以看出,readExact()可以兼容不同的方法調用。因此,若可以使用靜態的泛型方法,則不一定需要使用到協變。

??????? 從f2()中可以看出,泛型類的對象會在被實例化時確定下來。因此fruitReader的類型參數被確定成了Fruit


無界通配符

??????? 無界通配符<?>表示“一個泛型可以持有任何類型”,但在更多時候它是一種裝飾,告訴別人我考慮過Java泛型,并確定此處的這個泛型可以適配任何類型。

【例子:無界通配符的使用】

import java.util.HashMap;
import java.util.Map;public class UnboundedWildcards2 {static Map map1;static Map<?, ?> map2;static Map<String, ?> map3;static void assign1(Map map) {map1 = map;}static void assign2(Map<?, ?> map) {map2 = map;}static void assign3(Map<String, ?> map) {map3 = map;}public static void main(String[] args) {assign1(new HashMap());assign2(new HashMap());// 出現警告:assign3(new HashMap());assign1(new HashMap<>());assign2(new HashMap<>());assign3(new HashMap<>());}
}

??????? 第一次調用的assign3()會會發出警告,可以在編譯時添加-Xlint:unchecked來觀察這個警告:

編譯器似乎不會區分MapMap<?, ?>。下面的例子會展示出一點區別:

【例子:無界通配符帶來的區別】

import java.util.ArrayList;
import java.util.List;public class UnboundedWildcards1 {static List list1;static List<?> list2;static List<? extends Object> list3;static void assign1(List list) {list1 = list;list2 = list;// 會引發警告:list3 = list;}static void assign2(List<?> list) {list1 = list;list2 = list;list3 = list;}static void assign3(List<? extends Object> list) {list1 = list;list2 = list;list3 = list;}public static void main(String[] args) {assign1(new ArrayList());assign2(new ArrayList());// 也會引發警告:assign3(new ArrayList());assign1(new ArrayList<>());assign2(new ArrayList<>());assign3(new ArrayList<>());// 兩種定義都被List<?>接受List<?> wildList = new ArrayList();wildList = new ArrayList<>();assign1(wildList);assign2(wildList);assign3(wildList);}
}

??????? 這段代碼也會觸發一些警告:

這里體現了編譯器對List<?>List<? extends Object>在處理上的不同。

??????? 編譯器似乎并不關心ListList<?>之間有何區別,因此對它們的處理才會如此相同。然而,盡管這二者都可以被看做List<Object>,但在細節上它們仍有區別,它們實際的指代如下:

  • List:實際上表示“持有任何Object類型的原生List”。
  • List<?>:持有某種具體類型的非原生List(不過我們并不知道具體類型是什么)。

??????? 不過,在一些情況下,編譯器仍會區分二者:

【例子:區分不同的泛型】

public class Wildcards {static void rawArgs(Holder holder, Object arg) {// 會觸發警告:holder.set(arg);// 當前作用域中也沒有T,所以不能這樣寫:// T t = holder.get();// 可以這么寫,但會丟失類型信息:Object obj = holder.get();}// 與rawArgs()不同,方法會觸發報錯:static void unboundedArg(Holder<?> holder, Object arg) {// 發生報錯:// holder.set(arg);// 當然,這樣依舊不行:// T t = holder.get();// 可以,但還是會丟失類型信息:Object obj = holder.get();}static <T> T exact1(Holder<T> holder) {return holder.get();}static <T> T exact2(Holder<T> holder, T arg) {holder.set(arg);return holder.get();}static <T>T wildSubtype(Holder<? extends T> holder, T arg) {// 依舊會發生報錯:// holder.set(arg);return holder.get();}static <T>void wildSupertype(Holder<? extends T> holder, T arg) {// 引發報錯:// holder.set(arg);Object obj = holder.get();}public static void main(String[] args) {Holder raw = new Holder<>();// 這種寫法也一樣:raw = new Holder();Holder<Long> qualified = new Holder<>();Holder<?> unbounded = new Holder<>();Holder<? extends Long> bounded = new Holder<>();Long lng = 1L;rawArgs(raw, lng);rawArgs(qualified, lng);rawArgs(unbounded, lng);rawArgs(bounded, args);unboundedArg(raw, lng);unboundedArg(qualified, lng);unboundedArg(unbounded, lng);unboundedArg(bounded, lng);// 引發警告:Object r1 = exact1(raw);Long r2 = exact1(qualified);Object r3 = exact1(unbounded); // 方法返回Object類型// 引發異常:// Long r4 = exact1(bounded);// 引發警告Long r5 = exact2(raw, lng);Long r6 = exact2(qualified, lng);// 引發報錯:// Long r7 = exact2(unbounded, lng);// 同樣會報錯:// Long r8 = exact2(bounded, lng);// 引發警告:Long r9 = wildSubtype(raw, lng);Long r10 = wildSubtype(qualified, lng);// 同樣會獲得Object類型Object r11 = wildSubtype(unbounded, lng);// 引發異常:Long r12 = wildSubtype(bounded, lng);// 引發警告:wildSupertype(raw, lng);wildSupertype(qualified, lng);wildSupertype(bounded, lng);}
}

??????? 先看rawArgs中的holder.set(),編譯時會產生警告:

由于這里使用的是Holder的原始類型,所以任何向set()中傳入的類型都會被向上轉型為Object。編譯器知道這種行為是不安全的,所以發出了警告。注意:使用原始類型,就意味著放棄了編譯時檢查

??????? 再看unboundedArg()中的holder.set(),與原生的Holder不同,使用Holder<?>時編譯器提示的警告級別是error

這是因為原生的Holder可以持有任何類型的組合,而Holder<?>只能持有由某種具體類型組合成的單類型集合,因此我們無法傳入一個Object

??????? 除此之外,exact1()exact2()也因為參數的不同而受到了不同的限制:

可以看到,exact2()所受的限制更大。

??? 若向一個有“具體的”泛型類型(即無通配符)參數的方法中傳入原生類型,就會產生警告。這是因為具體參數所需的信息并不存在于原生類型中。


捕獲轉換

??????? <?>有一個特殊的用法:可以向一個使用了<?>的方法傳入原生類型,編譯器可能可以推斷出具體的類型參數。這被稱為捕獲轉換,通過這種方式,我們可以捕獲未指定的通配符類型,將其轉換成具體的類型:

【例子:捕獲轉換的使用例】

?

public class CaptureConversion {static <T> void f1(Holder<T> holder) {T t = holder.get();System.out.println(t.getClass().getSimpleName());}static void f2(Holder<?> holder) {f1(holder); // 捕獲類型,并將具體的類型傳入f1()中}@SuppressWarnings("unchecked")public static void main(String[] args) {Holder raw = new Holder<>(1);// 若直接傳入f1()中,會產生警告f1(raw);// 但使用f2()就不會出現警告f2(raw);Holder rawBasic = new Holder();// 會產生警告:rawBasic.set(new Object());// 也不會出現警告f2(rawBasic);// 即使向上轉型為Holder<?>,依舊可以推斷出具體類型:Holder<?> wildcarded = new Holder<>(1.0);f2(wildcarded);}
}

??????? 程序執行的結果是:

??????? 需要注意的是,捕獲轉換經適用于“在方法中必須使用確切類型”的情況。我們無法從f2()方法中返回T,因為對f2()而言,T是未知的(因此,若需要返回值,我們需要自己傳入類型參數)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/164730.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/164730.shtml
英文地址,請注明出處:http://en.pswp.cn/news/164730.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何在AD的PCB板做矩形槽孔以及如何倒圓弧角

Altium Designer 22下載安裝教程-CSDN博客 如何在AD上創建完整的項目-CSDN博客 開始前&#xff0c;請先安裝后AD&#xff0c;并創建好項目。 目錄 1. 如何在AD的PCB板做矩形槽孔 2. 如何在AD的PCB板倒圓弧角 1. 如何在AD的PCB板做矩形槽孔 首先&#xff0c;我們進入上面創…

PTA 7-9 堆棧操作合法性

7-9 堆棧操作合法性 分數 20 全屏瀏覽題目 作者 DS課程組 單位 浙江大學 假設以S和X分別表示入棧和出棧操作。如果根據一個僅由S和X構成的序列&#xff0c;對一個空堆棧進行操作&#xff0c;相應操作均可行&#xff08;如沒有出現刪除時棧空&#xff09;且最后狀態也是棧空…

2023年11個最佳免費WordPress主題

如果您剛剛開始使用 WordPress&#xff0c;您可能會很自然地認為&#xff0c;只要免費的WordPress主題看起來像您想要的網站主題&#xff0c;那么它就很合適。不幸的是&#xff0c;事情并沒有那么簡單。這就是為什么在今天的文章中&#xff0c;我們概述了一份可靠的標準清單&am…

某基金公司趙哥“逆襲”了!!!

趙哥&#xff0c;在上海一家基金公司做運維主管。 平時工作的首要任務&#xff0c;就是保障公司各項信息系統的安全運行。 萬一系統運行中出現了一些重要問題&#xff0c;他還要負責進行調查、記錄與匯報... 總之&#xff0c;責任很重&#xff0c;該說不說&#xff0c;搞不好…

Java互聯網+公立醫院績效考核源碼

一、建設信息化醫院績效考核的意義 1.提高考核效率&#xff1a;通過信息化手段&#xff0c;可以將績效考核數據自動采集、整理、分析和報告&#xff0c;大大提高了考核效率&#xff0c;減少了人工干預和錯誤率。 2.增強考核公正性&#xff1a;信息化考核可以減少人為因素的干…

Electronica上海 Samtec 驗證演示 | FireFly?Micro Flyover System?

摘要/前言 在圓滿結束的2023慕尼黑上海電子展上&#xff0c;Samtec虎家團隊為觀眾帶來了前所未有的豐富體驗&#xff1a;產品展示、采訪、Demo演示、抽獎互動~ 尤其是Demo演示&#xff0c;虎家工程師FAE Marcus為大家帶來了數個精彩的產品與系統講解演示。其中更不乏合作伙伴…

Windows、VMware問題集合

Windows、VMware問題集合 一. Windows11安裝VMware17提升虛擬機性能1. 桌面右擊圖標點擊屬性——>兼容性&#xff0c;找到“以管理員身份運行此程序”勾選&#xff0c;最后點擊確定即可。2. 關閉win11的內核隔離功能。 二. VMware虛擬機報錯&#xff08;虛擬化性能計數器需要…

C語言——求分段函數 y=f(x)的值

求分段函數 yf(x)的值,f(x)的表達式如下: #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int x,y;printf("請輸入x的值&#xff1a;");scanf("%d",&x);if(x>5){yx3;}else if(x>0 && x<5){y0;}elsey2*x30;pr…

Python 基礎【四】--數據類型-字符串【2023.11.23】

1 .定義 字符串是 Python 的一種數據類型&#xff0c;它可以通過單引號 ‘、雙引號 "、三引號 ‘’’ 或 “”"來定義。 aabcd bacsdcd c"""accsfv""" print(a) print(b) print(c)2 .基本操作 訪問單個字符 注意&#xff1a;從0開始…

Java_注解

1. 簡介 在Java中&#xff0c;注解&#xff08;Annotation&#xff09;是一種元數據形式&#xff0c;它為代碼添加了額外的信息&#xff0c;這些信息可以被編譯器、工具、框架或運行時環境使用。注解提供了一種聲明性的方式來向程序中添加元數據&#xff0c;而不需要修改程序的…

Harmony Ble藍牙App(二)連接與發現服務

Ble藍牙App&#xff08;二&#xff09;連接與發現服務 前言正文一、BlePeripheral回調二、連接和斷連三、連接狀態回調四、發現服務五、服務提供者六、顯示服務七、源碼 前言 在上一篇中我們進行掃描設備的處理&#xff0c;本文中進行連接和發現服務的數據處理&#xff0c;運行…

Mysql數據庫 18.Mysql SQL優化

SQL優化 一、插入優化 多條插入語句&#xff0c;影響執行效率 優化方案 1、批量插入&#xff1a; 在一條insert語句中多條數據&#xff0c;但是如果數據量過大&#xff0c;也不能完全使用一條語句語句&#xff0c;建議數據量為一次性插入1000條以下的數據 如果數據量多大&…

plantUML學習與實戰

背景 在日常工作或者生活中&#xff0c;使用交互圖來描述想法&#xff0c;往往相對于文字來說&#xff0c;可讀性更高&#xff0c;同時一定程度上可以提高溝通效率&#xff0c;但是苦于&#xff0c;不想對一堆控件拖拖拉拉&#xff0c;本人就是一個很討厭畫圖&#xff0c;但是…

【華為OD題庫-036】跳格子2-java

題目 小明和朋友玩跳格子游戲&#xff0c;有n個連續格子組成的圓圈&#xff0c;每個格子有不同的分數&#xff0c;小朋友可以選擇從任意格子起跳&#xff0c;但是不能跳連續的格子&#xff0c;不能回頭跳&#xff0c;也不能超過一圈:給定一個代表每個格子得分的非負整數數組&am…

Python---把函數的返回值作為另外一個函數的參數

def test1():return 50def test2(num):print(num)# 1. 保存函數test1的返回值 result test1()# 2.將函數返回值所在變量作為參數傳遞到test2函數 test2(result) # 50

數據結構 棧和隊列的應用

在昨天分享了有關棧和隊列的基礎知識和基本操作后&#xff0c;今天來分享一些有關棧和隊列的應用 棧和隊列的應用 刪除字符串中的所有相鄰重復項 #include <iostream> #include <stack> using namespace std; string remove(string S) {stack<char> charS…

MySql表中添加emoji表情

共五處需要修改。 語句執行修改&#xff1a; ALTER TABLE xxxxx CONVERT TO CHARACTER SET utf8mb4;

微型計算機原理MOOC題

一、8254 1.掉坑了&#xff0c;AL傳到端口不意味著一定傳到的是低位&#xff0c;要看控制字D5和D4&#xff0c;10是只寫高位&#xff0c;所以是0A00.。。 2. 3. 4.待解決&#xff1a;

優化C++資源利用:探索高效內存管理技巧

W...Y的主頁 &#x1f60a; 代碼倉庫分享&#x1f495; &#x1f354;前言&#xff1a; 我們之前在C語言中學習過動態內存開辟&#xff0c;使用malloc、calloc與realloc進行開辟&#xff0c;使用free進行堆上內存的釋放。進入C后對于動態內存開辟我們又有了新的內容new與dele…

CCC聯盟——UWB MAC(一)

本文在前面已經介紹了相關UWB的PHY之后&#xff0c;重點介紹數字鑰匙&#xff08;Digital Key&#xff09;中關于MAC層的相關實現規范。由于MAC層相應涉及內容比較多&#xff0c;本文首先從介紹UWB MAC的整體框架&#xff0c;后續陸續介紹相關的網絡、協議等內容。 1、UWB MAC架…