java教程筆記(十一)-泛型

Java 泛型(Generics)是 Java 5 引入的重要特性之一,它允許在定義類、接口和方法時使用類型參數。泛型的核心思想是將類型由具體的數據類型推遲到使用時再確定,從而提升代碼的復用性和類型安全性。

1.泛型的基本概念

1. 什么是泛型?

泛型的本質是參數化類型。參數化類型是指帶有類型參數的類或接口在定義類或方法時不指定具體的類型,而是在實例化時傳入具體的類型。

  • 泛型中不能寫基本數據類型
  • 指定具體的泛型類型后,傳遞數據時,可以傳遞該類類型及其子類類型
  • 如果不寫泛型,類型默認為Object
/*
List<E> 是 java.util 包下的接口。
E(Element)是類型參數,表示集合中元素的類型。
在代碼中你看到的 List<T> 實際上是程序員習慣使用的泛型變量名,與 List<E> 等價。
*/public interface List<E> extends Collection<E> { ... }/*
List<E> 是一個泛型接口(類型參數為 E)
List<String> 是一個參數化類型(String 是類型實參)
*/List<String> list = new ArrayList<>(); 
list.add("hello"); 
String str = list.get(0); // 無需強制轉換

2.為什么需要泛型?

在沒有泛型的情況下,集合類默認存儲的是?Object?類型,這意味著你可以往集合中添加任何類型的對象,但取出來時需要手動強制轉換,容易引發?ClassCastException

示例:非泛型帶來的問題

List list = new ArrayList();
list.add("hello");
list.add(100); // 編譯通過String str = (String) list.get(1); // 運行時報錯:ClassCastException

?使用泛型后

泛型確保了編譯期的類型檢查,避免運行時類型轉換錯誤。

List<String> list = new ArrayList<>();
list.add("hello");
// list.add(100); // 編譯錯誤,不能添加 Integer 類型
String str = list.get(0); // 不需要強制轉換

泛型允許我們編寫通用的類、接口和方法,而無需為每種數據類型重復實現相同邏輯。

示例:一個通用的容器類

public class Box<T> {private T item;public void setItem(T item) {this.item = item;}public T getItem() {return item;}
}

你可以這樣使用:

?一份代碼支持多種類型,提高復用性和可維護性。

Box<String> stringBox = new Box<>();
stringBox.setItem("Hello");
String s = stringBox.getItem(); // 直接獲取String類型Box<Integer> intBox = new Box<>();
intBox.setItem(123);
Integer i = intBox.getItem();

避免強制類型轉換(Avoid Casting)

在沒有泛型時,從集合中取出元素必須進行強制類型轉換,這不僅繁瑣,還可能出錯。

非泛型寫法

List list = new ArrayList(); 
list.add("hello"); 
String str = (String) list.get(0); // 強制轉換

泛型寫法

?泛型讓代碼更簡潔、清晰,減少出錯機會。

List<String> list = new ArrayList<>(); 
list.add("hello");String str = list.get(0); // 自動類型匹配

3. 泛型的優點

特性描述
類型安全避免運行時 ClassCastException
自動類型轉換不需要手動強轉
代碼復用使用泛型編寫通用邏輯

2.泛型的使用方式

1. 泛型類

通過在類名后加上?<T>?來聲明一個泛型類,T?是類型參數(Type Parameter)。可以表示屬性類型、方法的返回值類型、參數類型

創建該對象時,該標識確定類型

靜態方法不能使用類級別的泛型參數(如class MyClass<T>中的T),但可以定義自己的泛型參數。

/*
<>括號中的標識是任意設置的,用來表示類型參數,指代任何數據類型T :代表一般的任何類。E :代表 Element 元素的意思,或者 Exception 異常的意思。K :代表 Key 的意思。V :代表 Value 的意思,通常與 K 一起配合使用。S :代表 Subtype 的意思,文章后面部分會講解示意。
*/
public class Box<T> {private T item;public void setItem(T item) { 
this.item = item; 
} 
public T getItem() { 
return item; 
} 
} 
// 使用 
Box<String> stringBox = new Box<>(); 
stringBox.setItem("Hello"); 
Box<Integer> integerBox = new Box<>(); 
integerBox.setItem(123);
//多個泛型參數
public class Pair<K, V> {private K key;private V value;public Pair(K key, V value) {this.key = key;this.value = value;}public K getKey() { return key; }public V getValue() { return value; }
}

泛型類的繼承

子類也可以保留父類的泛型特性?

public class NumberBox<T extends Number> extends Box<T> {public double getDoubleValue() {return getValue().doubleValue();}
}

2. 泛型接口

  • T?表示實體類型(如 User、Product)。
  • ID?表示主鍵類型(如 Long、String)。
public interface Repository<T, ID> {T findById(ID id);void save(T entity);void deleteById(ID id);
}
public interface Repository<T, ID> { 
T findById(ID id); 
void save(T t); 
} public class UserRepository implements Repository<User, Long> { 
@Override 
public User findById(Long id) { 
return null; 
}@Override 
public void save(User user) {}}

實現泛型接口并保留泛型

如果希望實現類也保持泛型特性,可以這樣做:

public class GenericRepository<T, ID> implements Repository<T, ID> { 
@Override public T findById(ID id) { 
// 泛型實現邏輯 
return null;} 
@Override public void save(T entity) { 
// 泛型保存邏輯 
} 
@Override public void deleteById(ID id) { 
// 泛型刪除邏輯}}

調用示例:

GenericRepository<User, Long> userRepository = new GenericRepository<>(); 
User user = userRepository.findById(1L); 
userRepository.save(user);

3. 泛型方法

泛型方法的定義需要在返回類型前使用?<T>?來聲明一個類型參數,其中?T?是一個占位符,表示任意類型。

方法中參數類型不確定時,泛型方案選擇:

1.使用類名后面定義的泛型,所有方法都能用

2.在方法申明上定義自己的泛型,只有本方法能用

/*
<T>:聲明一個類型參數。
T value:接收任何類型的參數。
*/
public <T> void printValue(T value) {System.out.println(value);
}
printValue(10);       // 整數
printValue("Hello");  // 字符串
printValue(3.14);     // 浮點數
public class Utils { 
public static <T> void printArray(T[] array) { 
for (T item : array) { 
System.out.println(item);} 
} 
} 
// 調用 
Utils.<String>printArray(new String[]{"A", "B"}); 
Utils.printArray(new Integer[]{1, 2, 3}); // 類型推斷
//泛型方法也可以返回泛型類型的數據
public <T> T getValue(T defaultValue) {return defaultValue;
}String result = getValue("Default");
Integer number = getValue(100);

?4.泛型類與泛型接口的區別

特性泛型類泛型接口
定義方式class ClassName<T>interface InterfaceName<T>
主要用途封裝通用的數據結構或行為定義通用的行為規范
實現方式直接實例化使用需要被類實現后再使用
類型約束可以通過?extends?限制類型同樣支持?extends?約束
多類型參數支持多個泛型參數同樣支持多個泛型參數

3.泛型通配符

在 Java 泛型中,通配符(Wildcard)?是一種特殊的類型參數,用于表示未知的類型。它增強了泛型的靈活性,特別是在集合類的操作中非常有用。

1.為什么需要泛型通配符?

1.?泛型不具備多態性

在 Java 中,即使?Dog?是?Animal?的子類,List<Dog>?并不是?List<Animal>?的子類型。也就是說,泛型是不變的)即泛型類型之間不繼承其參數類型的多態關系。

List<Dog> dogs = new ArrayList<>();
// List<Animal> animals = dogs; // 編譯錯誤!不能這樣賦值

2.為什么泛型不具備多態性?

1.?為了保證類型安全

如果允許?List<Dog>?賦值給?List<Animal>,就會帶來潛在的類型不安全風險。

假設允許這種賦值:
List<Dog> dogs = new ArrayList<>(); 
List<Animal> animals = dogs; 
// 如果允許 animals.add(new Cat()); // 合法嗎?理論上可以,因為 Cat 是 Animal 子類Dog dog = dogs.get(0); // 錯誤 ClassCastException!

這會導致運行時異常,破壞了類型安全性。

因此,Java 在編譯期就禁止了這種行為。

3.對比數組的協變性

Java 中的數組是協變的(covariant),即:

Dog[] dogs = new Dog[3]; Animal[] animals = dogs; //  合法

但這其實也存在安全隱患,例如:

animals[0] = new Cat(); // 運行時報錯:ArrayStoreException

所以,Java 數組的協變性是在運行時進行類型檢查的,而泛型為了避免這種風險,在編譯期就禁止了這種操作。

如果你寫一個方法用于打印列表中的元素,你可能希望它能接受任何類型的?List,比如?List<String>List<Integer>?等。?那么就需要泛型具有多態性,由此就出現了通配符

4.通配符的類型?

1.上界通配符(只能進行只讀操作

在 Java 泛型中,上界通配符?<? extends T>?是一種特殊的泛型表達方式,用于表示某個類型是?T?或其子類型。它提供了一種靈活的方式來處理具有繼承關系的泛型集合。

List<? extends T> list;
  • ?:表示未知類型。
  • extends T:表示該未知類型是?T?或其子類。
List<? extends Number> numbers = new ArrayList<Integer>();

?合法賦值包括:

  • List<Integer>
  • List<Double>
  • List<AtomicInteger>
  • 等等?Number?的子類列表
1.為什么使用上界通配符?
1.?允許讀取為父類型

你可以安全地將集合中的元素當作?T?類型來讀取。

public void printNumbers(List<? extends Number> numbers) {for (Number number : numbers) {System.out.println(number);}
}

安全地讀取為?Number,無論實際是?Integer?還是?Double。?

List<Integer> ints = List.of(1, 2);
List<Double> doubles = List.of(3.5, 4.5);printNumbers(ints);   // ? 合法
printNumbers(doubles); // ? 合法
2.?避免類型不安全的寫入

雖然可以讀取,但不能向?<? extends T>?集合中添加除?null?外的任何對象。

List<? extends Number> list = new ArrayList<Integer>(); // 
list.add(10); //  編譯錯誤! 
list.add(null); // 合法(但幾乎無意義)
?2.為什么上界通配符只能進行只讀操作
List<Integer> integers = new ArrayList<>();
List<? extends Number> list = integers;// list.add(10);       //  編譯錯誤!
// list.add(new Integer(5)); //  同樣不允許

雖然我們知道?list?實際上是一個?List<Integer>,并且可以添加?Integer?類型的值,但編譯器無法確定?? extends Number?到底是?IntegerDouble?還是其他子類,所以為了保證類型安全,直接禁止寫入操作

假設允許寫入會發生什么?

List<Integer> intList = new ArrayList<>();List<? extends Number> list = intList; 
list.add(3.14); // 如果允許,會怎樣?Integer i = intList.get(0); //  ClassCastException!
  • 3.14?是?Double?類型。
  • 雖然它是?Number?的子類,但?intList?只能存儲?Integer
  • 此時如果允許寫入,就會破壞?intList?的類型一致性。

因此,Java 在編譯期就阻止了這種風險

為什么可以添加 null?

list.add(null); // ?合法

  • null?是所有引用類型的合法值。
  • 它不違反任何類型約束,因為?null?可以被當作任何類型來處理。

2.下界通配符(只寫不可讀)

在 Java 泛型中,下界通配符?<? super T>?表示一個未知類型,它是?T?或其任意父類。這種通配符用于增強泛型的靈活性,特別是在需要向集合中寫入數據時。

List<? super Integer> list;
  • ? super Integer:表示該列表可以是?IntegerNumber?或?Object?類型的列表。
  • 合法賦值包括:
    List<Integer> integers = new ArrayList<>(); 
    List<Number> numbers = new ArrayList<>();List<Object> objects = new ArrayList<>(); 
    List<? super Integer> list1 = integers; //  允許List<? super Integer> list2 = numbers; // 允許 
    List<? super Integer> list3 = objects; //  允許
    1.為什么下界通配符只能寫入,不能讀?

你可以安全地向?<? super T>?集合中添加?T?類型或其子類型的對象。

public void addIntegers(List<? super Integer> list) { 
list.add(10); //  合法 
list.add(new Integer(5)); //  合法}

原因:

  • 編譯器知道?? super Integer?是?Integer?的父類之一(如?Number?或?Object)。
  • 所以你傳入一個?Integer,它一定能被接受(因為它是所有可能類型的子類)。

不能讀取為具體類型的原因:

雖然你可以寫入?Integer,但你無法確定從集合中讀出的元素是什么類型。

List<? super Integer> list = new ArrayList<Number>();Object obj = list.get(0); //  只能讀作 Object // Integer i = list.get(0); //  編譯錯誤
原因:
  • list?實際上可能是?List<Number>?或?List<Object>
  • 所以編譯器不能保證返回的對象一定是?Integer,只能保證是?Object?類型。

3.無限定通配符?

在 Java 泛型中,無限定通配符?<?>?是一種特殊的泛型表達方式,表示“某種未知類型”。它用于定義一個可以接受任何泛型類型的集合或對象。

List<?> list;
  • ?:表示一個未知的類型。
  • 可以賦值為任何泛型類型的集合:
    List<String> stringList = new ArrayList<>();List<Integer> intList = new ArrayList<>(); 
    List<?> list1 = stringList; //  合法 
    List<?> list2 = intList; // 合法
    1.為什么使用無限定通配符?
1.?適用于只讀操作(但只能讀作 Object)

你可以遍歷集合并讀取元素,但只能當作?Object?類型處理:

public void printList(List<?> list) { 
for (Object obj : list) { 
System.out.println(obj); 
} 
}

調用示例:

printList(stringList); //  輸出字符串printList(intList); // 輸出整數
?注意:

你不能向?List<?>?中添加任何非?null?元素:

list.add("test"); //  編譯錯誤
list.add(10); //  編譯錯誤list.add(null); //  合法,但幾乎無意義

因為編譯器不知道???到底是什么類型,為了保證類型安全,禁止寫入。

4.通配符的對比

特性無限定通配符?<?>上界通配符?<? extends T>下界通配符?<? super T>
表示類型任意未知類型T?或其子類T?或其父類
讀取能力? 只能讀作?Object? 可讀為?T? 可讀為?Object
寫入能力? 不允許(除?null? 不允許(除?null? 可寫入?T?類型
使用場景通用只讀操作生產者(只讀)消費者(只寫)

4.PECS 原則詳解

PECS(Producer Extends, Consumer Super)?是 Java 泛型中一個非常重要的設計原則,用于指導在使用泛型通配符時如何選擇合適的通配符類型,以確保類型安全和代碼靈活性。

1.PECS 的含義

角色描述使用的通配符
Producer(生產者)只從集合中讀取數據<? extends T>
Consumer(消費者)只向集合中寫入數據<? super T>

? 簡單記憶:讀用 extends,寫用 super

2.詳細解釋

1.?Producer Extends

當你只需要從集合中讀取數據,并且希望集合可以接受?T?或其子類的任意一種類型時,使用?<? extends T>

public void process(List<? extends Number> numbers) {for (Number number : numbers) { 
System.out.println(number.doubleValue());} 
}

調用示例:

List<Integer> ints = List.of(1, 2); 
List<Double> doubles = List.of(3.5, 4.5); 
process(ints); //  合法 
process(doubles); //  合法
  • ?優點:可以安全地讀取為?Number
  • ?缺點:不能寫入任何非?null?元素
2.?Consumer Super

當你只需要向集合中寫入數據,并希望集合能接受?T?類型及其父類的集合時,使用?<? super T>

public void addNumbers(List<? super Integer> list) { list.add(10); list.add(20); }

調用示例:

List<Number> numbers = new ArrayList<>(); addNumbers(numbers); // ? 合法

  • ?優點:可以安全地寫入?Integer?或其子類對象
  • ?缺點:只能讀作?Object,無法還原為具體類型

3.為什么需要 PECS?

Java 泛型不具備多態性(Invariance),即即使?Dog?是?Animal?的子類,List<Dog>?也不是?List<Animal>?的子類。這導致我們在處理集合時面臨類型兼容性的挑戰。

通過使用通配符并遵循 PECS 原則,我們可以在保持類型安全的前提下,寫出更加通用、靈活的代碼。

4.典型應用示例

1.?生產者 + 消費者組合使用

public static <T> void copy(List<? super T> dest, List<? extends T> src) { for (T item : src) { dest.add(item); } }

  • src?是生產者 → 使用?<? extends T>
  • dest?是消費者 → 使用?<? super T>

調用示例:

List<Integer> source = List.of(1, 2, 3); List<Number> target = new ArrayList<>(); copy(target, source); // ? 合法

5.總結

內容描述
PECS 原則Producer Extends, Consumer Super
核心思想根據集合是“讀”還是“寫”來選擇合適的通配符
優勢提高代碼復用性、增強類型安全性
限制不能同時作為生產者和消費者
最佳實踐在泛型集合操作中優先考慮通配符,避免直接使用具體泛型類型

理解并掌握 PECS 原則,是編寫高質量 Java 泛型代碼的關鍵所在。它幫助你在保持類型安全的同時,實現更通用、更靈活的設計。

?5.類型擦除(Type Erasure)

Java 的泛型類型擦除(Type Erasure)是 Java 泛型實現的核心機制之一,它指的是在編譯期間,泛型類型信息會被移除(擦除),以兼容非泛型的舊代碼(即 Java 5 之前的版本)。這意味著泛型只存在于編譯階段,在運行時并不存在具體的泛型類型

示例:

盡管?List<String>?和?List<Integer>?在源碼中指定了不同的泛型類型,但在運行時它們的類型都是?ArrayList泛型信息被擦除了

當把集合定義為string類型的時候,當數據添加在集合當中的時候,僅僅在門口檢查了一下數據是否符合String類型,? 如果是String類型,就添加成功,當添加成功以后,集合還是會把這些數據當做Object類型處理,當往外獲取的時候,集合在把他強轉String類型

List<String> list1 = new ArrayList<>(); 
List<Integer> list2 = new ArrayList<>(); 
System.out.println(list1.getClass() == list2.getClass()); // true

1.類型擦除的過程

1.?替換所有類型參數為原始類型

  • 類型參數如?<T>?被替換為其上界(upper bound)
  • 如果沒有指定上界,默認使用?Object

例如:

public class Box<T> {private T value; 
public void setValue(T value) { 
this.value = value; 
} 
public T getValue() {return value;} 
}

編譯后相當于:

public class Box { 
private Object value; p
ublic void setValue(Object value) { 
this.value = value; 
} 
public Object getValue() {return value;} 
}

2.?插入類型轉換代碼

編譯器會在適當的位置自動插入強制類型轉換,確保類型安全。

例如:

Box<String> box = new Box<>(); 
box.setValue("Hello"); 
String s = box.getValue(); // 編譯器自動插入 (String)box.getValue()

2.類型擦除的影響

影響說明
無法獲取泛型類型信息運行時無法通過反射獲取?List<String>?中的?String?類型
不能實例化泛型類型new T()?是非法的,因為運行時不知道?T?是什么
不能創建泛型數組T[] array = new T[10];?是非法的
重載方法沖突方法簽名在擦除后可能重復,導致編譯錯誤

示例:

public void process(List<String> list) {} 
public void process(List<Integer> list) {} // 編譯錯誤:方法簽名沖突

3.如何繞過類型擦除(獲取泛型信息)

雖然 Java 擦除了泛型信息,但在某些情況下可以通過反射獲取泛型類型信息,前提是該泛型類型是在聲明時明確指定的(不是變量類型)。

示例:獲取父類的泛型類型

abstract class Base<T> { 
abstract T get(); 
} 
class StringSub extends Base<String> {@Override String get() { return null; } } // 獲取泛型類型 
Type type = StringSub.class.getGenericSuperclass(); 
if (type instanceof ParameterizedType pt) { 
Type actualType = pt.getActualTypeArguments()[0]; 
System.out.println(actualType); // 輸出: class java.lang.String 
}

5.泛型與繼承

  • 子類可以繼承父類并指定泛型類型。
  • 子類也可以繼續保留泛型參數。
class Animal {} 
class Dog extends Animal {} 
class Cage<T> { 
private T animal;
public void set(T animal) { 
this.animal = animal;} 
public T get() { 
return animal; 
} 
} 
class DogCage extends Cage<Dog> { // 此處 T 已經固定為 Dog }

6.泛型常見錯誤

錯誤示例原因
List<int>泛型不能使用基本類型,應使用?List<Integer>
new T()編譯器不知道?T?是什么類型
new List<String>[]泛型數組不可創建
if (obj instanceof List<String>)泛型被擦除,無法判斷

7.Java 明確禁止創建具體泛型參數類型的數組

?在 Java 中,泛型數組(如?List<Dog>[])與單個泛型對象(如?List<Integer>)的創建規則完全不同,核心區別在于?數組的協變性(Covariance)?和?泛型的不變性(Invariance)。以下是詳細解釋:

?類型擦除

Java 的泛型是通過編譯時的類型檢查實現的,但在運行時,泛型信息會被擦除。例如:

List<Dog> list1 = new ArrayList<>(); 
List<Cat> list2 = new ArrayList<>(); 
// 運行時 list1 和 list2 都是 List 類型

所以當你嘗試創建一個?ArrayList<Dog>[10]?時,運行時實際上只能看到?ArrayList[],而無法區分里面存儲的是?List<Dog>?還是?List<Cat>

數組協變性

Java 數組是協變的(covariant),即:

String[] strings = new String[10]; Object[] objects = strings; // 合法

1. 為什么?List<Dog>[] listArray = new ArrayList<Dog>[10];?不可以?

1.1 核心原因:泛型數組的類型安全問題

Java 的泛型是通過?類型擦除(Type Erasure)?實現的,即泛型信息在運行時被移除。而?數組在運行時保留類型信息,并且支持協變性(Dog[]?是?Animal[]?的子類型),這會導致類型不安全。

示例:泛型數組的潛在風險

// 假設允許創建泛型數組 
List<Dog>[] listArray = new ArrayList<Dog>[10];// 插入錯誤類型的 List(Dog 是 Animal 的子類)List<Animal> animalList = new ArrayList<>();listArray[0] = animalList; // 編譯通過,但實際類型不匹配! 
// 后續訪問時可能出現 ClassCastException 
Dog dog = listArray[0].get(0); // 如果 animalList 中有 Cat,此處拋出異常
  • 問題List<Dog>?和?List<Animal>?沒有繼承關系(泛型是不變的),但數組的協變性允許將?List<Animal>?賦值給?List<Dog>[],導致運行時類型不一致。

1.2 Java 的設計限制

Java 禁止直接創建泛型數組,因為:

  1. 運行時無法驗證數組元素的類型(類型擦除導致)。
  2. 數組的協變性與泛型的不變性沖突,可能引發類型不安全。

2. 為什么?List<Integer> list01 = new ArrayList<>();?可以?

2.1 鉆石操作符(Diamond Operator)

  • Java 7 引入:允許在實例化泛型類時省略類型參數,編譯器根據上下文自動推斷類型。
  • 示例
    List<Integer> list01 = new ArrayList<>(); //  合法
    • 編譯器推斷?ArrayList<>?為?ArrayList<Integer>
    • 等價于顯式聲明:List<Integer> list01 = new ArrayList<Integer>();

2.2 為什么這是安全的?

  • 單個對象的類型是固定的ArrayList<Integer>?僅存儲?Integer?類型元素,不會出現多態賦值問題。
  • 泛型的不變性不影響單個對象:無需考慮數組的協變性問題。

3. 關鍵區別總結

復制

特性泛型數組(如?List<Dog>[]單個泛型對象(如?List<Integer>
類型檢查時機運行時檢查(數組保留類型信息)編譯時檢查(泛型通過類型擦除實現)
協變性支持協變性(Dog[]?是?Animal[]?的子類型)不支持協變性(List<Dog>?與?List<Animal>?無繼承關系)
類型安全無法保證(可能插入錯誤類型)完全保證(編譯器強制類型匹配)
Java 允許性?不允許(編譯警告或錯誤)允許(鉆石操作符合法)

4. 替代方案:如何安全創建泛型數組?

如果需要存儲泛型集合的數組,推薦以下方式:

4.1 使用通配符數組

List<?>[] listArray = new ArrayList<?>[10]; //  安全創建
listArray[0] = new ArrayList<Dog>(); 
listArray[1] = new ArrayList<Animal>(); // 合法,但只能讀取(不能添加元素)
  • 限制:不能向?List<?>?中添加元素(除了?null)。

4.2 使用嵌套集合

List<List<Dog>> listList = new ArrayList<>();listList.add(new ArrayList<>()); // 安全
  • 優點:完全利用泛型的類型安全性,避免數組的協變性問題。

5. 總結

  • 泛型數組不可創建:由于類型擦除和數組的協變性,Java 禁止直接創建泛型數組(如?List<Dog>[]),以避免運行時類型不安全。
  • 單個泛型對象可創建:使用鉆石操作符?<>(Java 7+)可安全創建單個泛型對象(如?List<Integer>),因為類型推斷在編譯期完成,且不涉及多態賦值。

通過理解數組和泛型的設計差異,可以更安全地編寫 Java 代碼,避免潛在的類型錯誤。

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

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

相關文章

力扣刷題(第四十九天)

靈感來源 - 保持更新&#xff0c;努力學習 - python腳本學習 反轉鏈表 解題思路 迭代法&#xff1a;通過遍歷鏈表&#xff0c;逐個改變節點的指針方向。具體步驟如下&#xff1a; 使用三個指針&#xff1a;prev&#xff08;初始為None&#xff09;、curr&#xff08;初始為…

設置應用程序圖標

(1)找一張圖片 (2)然后轉ico圖片 在線生成透明ICO圖標——ICO圖標制作 驗證16x16就可以 降低exe大小 (3) 在xxx.pro修改 添加 &#xff08;4&#xff09; 刪除 build 和 xxxpro_user文件 (5)編譯project 和運行xx.exe (6)右鍵 設置快捷方式

免費wordpress模板下載

西瓜紅色的免費wordpress模板&#xff0c;簡潔實用又容易上手&#xff0c;適合新手使用。 下載 https://www.waimaoyes.com/moban/2231.html

【React】React 18 并發特性

React 18 引入了 并發特性&#xff08;Concurrent Features&#xff09;&#xff0c;這是一次對 React 渲染機制的重大升級&#xff0c;讓 React 更加智能、響應更流暢、資源更節省。 我們來詳細講解一下它的原理、特性、API 以及實際應用。 &#x1f9e0; 一、什么是并發特性…

FFMPEG 提取視頻中指定起始時間及結束時間的視頻,給出ffmpeg 命令

以下是提取視頻中指定起始時間及結束時間的 ffmpeg 命令示例: bash 復制 ffmpeg -i input.mp4 -ss 00:01:30.00 -to 00:05:00.00 -c copy output.mp4 其中,-i input.mp4 是指定要處理的輸入視頻文件為 “input.mp4”。 -ss 00:01:30.00 表示指定視頻的起始時間為 1 分 30 …

mybatis的if判斷==‘1‘不生效,改成‘1‘.toString()才生效的原因

mybatis的xml文件中的if判斷‘1’不生效&#xff0c;改成’1’.toString()才生效 Mapper接口傳入的參數 List<Table> queryList(Param("state") String state);xml內容 <where><if test"state ! null and state 1">AND EXISTS(select…

AI 模型分類全解:特性與選擇指南

人工智能&#xff08;AI&#xff09;技術正以前所未有的速度改變著我們的生活和工作方式。AI 模型作為實現人工智能的核心組件&#xff0c;種類繁多&#xff0c;功能各異。從簡單的線性回歸模型到復雜的深度學習網絡&#xff0c;從文本生成到圖像識別&#xff0c;AI 模型的應用…

01-python爬蟲-第一個爬蟲程序

開始學習 python 爬蟲 第一個獲取使用最多的網站-百度 源代碼 并將源代碼保存到文件中 from urllib.request import urlopenurl https://www.baidu.com resp urlopen(url)with open(baidu.html, w, encodingutf-8) as f:f.write(resp.read().decode(utf-8))知識點&#xf…

四六級監考《培訓學習》+《培訓考試》

1 線上注冊 &#xff08;網址&#xff1a; https://passport.neea.edu.cn 2 登錄培訓平臺參加線上必修課程學習和考核 &#xff08;平臺網址&#xff1a; https://kwstudy.neea.edu.cn 注意選擇學員入口&#xff09; 3 考試要求&#xff1a;考試成績須達應到80分以上&#xf…

回顧Java與數據庫的30年歷程

當 Java 1.0 于 1996 年推出時&#xff0c;語言和互聯網都與今天大不相同。當時&#xff0c;網絡主要是靜態的&#xff0c;而 Java 承諾通過注入交互式游戲和動畫來為網絡注入活力&#xff0c;這一承諾極具前景。根據 1995 年寫給《連線》雜志的 David Banks 的說法&#xff0c…

simulink有無現成模塊可以實現將三個分開的輸入合并為一個[1*3]的行向量輸出?

提問 simulink有無現成模塊可以實現將三個分開的輸入合并為一個[1*3]的行向量輸出&#xff1f; 回答 Simulink 本身沒有一個單獨的模塊能夠直接將三個分開的輸入合并成一個 [13] 行向量輸出&#xff0c;但是可以通過 組合模塊實現你要的效果。 ? 推薦方式&#xff1a;Mux …

代碼訓練LeetCode(24)數組乘積

代碼訓練(24)LeetCode之數組乘積 Author: Once Day Date: 2025年6月5日 漫漫長路&#xff0c;才剛剛開始… 全系列文章可參考專欄: 十年代碼訓練_Once-Day的博客-CSDN博客 參考文章: 238. 除自身以外數組的乘積 - 力扣&#xff08;LeetCode&#xff09;力扣 (LeetCode) 全…

NLP學習路線圖(十七):主題模型(LDA)

在浩瀚的文本海洋中航行&#xff0c;人類大腦天然具備發現主題的能力——翻閱幾份報紙&#xff0c;我們迅速辨別出"政治"、"體育"、"科技"等板塊&#xff1b;瀏覽社交媒體&#xff0c;我們下意識區分出美食分享、旅行見聞或科技測評。但機器如何…

vue對axios的封裝和使用

在 Vue 項目中&#xff0c;使用 axios 進行 HTTP 請求是非常常見的做法。為了提高代碼的可維護性、統一錯誤處理和請求攔截/響應攔截邏輯&#xff0c;對axios進行封裝使用。 一、基礎封裝&#xff08;適用于 Vue 2 / Vue 3&#xff09; 1. 安裝 axios npm install axios2. 創…

HTML實現端午節主題網站:龍舟爭渡,憑吊祭江誦君賦。

名人說:龍舟爭渡,助威吶喊,憑吊祭江誦君賦。——蘇軾《六幺令天中節》 創作者:Code_流蘇(CSDN)(一個喜歡古詩詞和編程的Coder??) 目錄 一、項目概覽:傳統與現代的技術碰撞1. 核心特性一覽2. 網站結構設計二、技術亮點深度解析1. 響應式布局的精妙設計2. CSS動畫系統的…

【Redis】筆記|第9節|Redis Stack擴展功能

Redis Stack 擴展功能筆記&#xff08;基于 Redis 7&#xff09; 一、Redis Stack 概述 定位&#xff1a;Redis OSS 擴展模塊&#xff08;JSON、搜索、布隆過濾器等&#xff09;&#xff0c;提供高級數據處理能力。核心模塊&#xff1a; RedisJSON&#xff1a;原生 JSON 支持…

如何選擇專業數據可視化開發工具?為您拆解捷碼全功能和落地指南!

分享大綱&#xff1a; 1、捷碼核心功能&#xff1a;4維能力支撐大屏開發 2、3步上手&#xff1a;可視化大屏開發操作路徑 3、適配場景&#xff1a;8大行業已驗證方案 在各行各業要求數字化轉型時代&#xff0c;數據可視化大屏已成為眾多企業數據驅動的核心工具。面對市場上繁雜…

測試W5500的第11步_使用ARP解析IP地址對應的MAC地址

本文介紹了基于W5500芯片的ARP協議實現方法&#xff0c;詳細闡述了ARP請求與回復的工作機制。ARP協議通過廣播請求和單播回復實現IP地址與MAC地址的映射&#xff0c;確保局域網設備間的可靠通信。文章提供了完整的STM32F10x開發環境下的代碼實現&#xff0c;包括網絡初始化、SP…

在樹莓派上添加音頻輸入設備的幾種方法

在樹莓派上添加音頻輸入設備可以通過以下步驟完成&#xff0c;具體方法取決于設備類型&#xff08;如USB麥克風、3.5mm接口麥克風或HDMI音頻輸入&#xff09;。以下是詳細指南&#xff1a; 1. 連接音頻輸入設備 USB麥克風/聲卡&#xff1a;直接插入樹莓派的USB接口。3.5mm麥克…

IDEA 打開文件亂碼

問題&#xff1a;文件亂碼 底部編碼無法切換 解決方案&#xff1a; 第一步 使用Nodepad 查詢文件編碼 本項目設置為 轉為 UTF-8 無 BOM 第二步&#xff1a;在 IntelliJ IDEA 中&#xff1a;右鍵點擊文件 → File Encoding → 選擇目標編碼&#xff08;如 UTF-8&#xff09; 最…