>[success] # java 泛型 -- 廣泛的參數類型
1. 以集合為例,可以存放不同類型的對象,是因為將所有對象都看做`Object`類型放入的,因此從集合中取出元素時也是`Object`類型,為了表達該元素真實的數據類型,則需要**強制類型轉換**,而強制類型轉換可能會引發類型**轉換異常**
~~~
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.創建一個list 集合
List ls = new ArrayList();
// add 向集合中添加元
ls.add("1"); // 末尾插入
ls.add(11111);
// 獲取元素
Object str = ls.get(0); // 獲取Object 類型
Integer i = (Integer) ls.get(1); // 強制類型轉換獲取 int 類型
System.out.println(str); // 1
System.out.println(i); // 11111
}
}
~~~
2. 從Java5開始增加**泛型機制**,也就是在集合名稱的右側使用的方式來明確要求該集合中**可以存放的元素類型**,若放入其它類型的元素則**編譯報錯**,Java7開始的新特性: 菱形特性 ? **就是后面<>中的數據類型可以省略**,實際上**泛型只在編譯時期有效,在運行時期不區分是什么類型**
~~~
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.創建一個list 集合
List<Integer> ls = new ArrayList<Integer>();
// List<Integer> ls = new ArrayList<>(); // 縮寫 Java7開始的新特性: 菱形特性 ? 就是后面<>中的數據類型可以省略
// add 向集合中添加元
// ls.add("1"); // 報錯
ls.add(11111);
}
}
~~~
3. 不能將不同泛型 互相賦值
~~~
import java.util.ArrayList;
import java.util.List;
public class ListTest {
public static void main(String[] args) {
// 1.創建一個list 集合
List<Integer> ls = new ArrayList<Integer>();
List<String> ls1 = new ArrayList<>();
// ls1 = ls; // Type mismatch: cannot convert from List<Integer> to List<String>Java(16777233)
}
}
~~~
4. 以集合為例 沒特意指定泛型其實默認泛型為`Object`


>[danger] ##### 泛型的本質
1. 泛型的本質就是**參數化類型**,讓**數據類型作為參數傳遞**,聲明泛型時候規定占位符相當于形參,實際使用時候傳入泛型類型相當于實參,使得實際參數可以傳遞各種各樣廣泛的數據類型,因此得名為泛型
* 以List 為例 E 其實就是泛型的形參,類型完全取決于使用時候傳入的實參決定的
~~~
public interface List<E> extends Collection<E>
List<String> ls = new ArrayList<>();
~~~
>[info] ## 泛型接口
1. 泛型接口和普通接口的區別就是后面添加了**類型參數列表**,可以有多個類型參數,如:`<E, T, .. >`
~~~
public interface List<E> extends Collection<E>
~~~
>[info] ## 自定義泛型類
1.泛型類和普通類的區別就是類名后面添加了**類型參數列表**,可以有多個類型參數,:`<E, T, .. >`
2. 實例化泛型類時應該指定具體的數據類型(沒有指定則默認為Object),并且是**引用數據類型**而不是基本數據類型
* 默認泛型


* 指定泛型

~~~
public class PersonTest<T> {
private int age;
private String name;
private T gender;
public PersonTest() {
}
public PersonTest(int age, String name, T gender) {
this.age = age;
this.name = name;
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getGender() {
return gender;
}
public void setGender(T gender) {
this.gender = gender;
}
@Override
public String toString() {
return "PersonTest [age=" + age + ", name=" + name + ", gender=" + gender + "]";
}
public static void main(String[] args) {
// 聲明使用
PersonTest per = new PersonTest(1, "w", '男');
per.setGender('女');
System.out.println(per); // PersonTest [age=1, name=w, gender=女]
// 指定泛型類型
PersonTest<Integer> per1 = new PersonTest<>(1, "w", 0);
per1.setGender(null); // 可以賦值null
per1.setGender(1);
System.out.println(per1); // PersonTest [age=1, name=w, gender=1]
}
}
~~~
3. 父類有泛型,子類可以選擇**保留泛型**也**可以選擇指定泛型類型**,子類除了指定或保留父類的泛型,還可以增加自己的泛型
~~~
//public class SubPerson extends PersonTest { // 不保留泛型并且沒有指定類型,此時Person類中的T默認為Object類型 擦除
//public class SubPerson extends PersonTest<String> { // 不保留泛型但指定了泛型的類型,此時Person類中的T被指定為String類型
// public class SubPerson<T> extends PersonTest<T> { // 保留父類的泛型 可以在構造對象時來指定T的類型
public class SubPerson<T, T1> extends PersonTest<T> { // 保留父類的泛型,同時在子類中增加新的泛型
T1 z;
public static void main(String[] args) {
// 第一種默認是Object 泛型
// SubPerson sp1 = new SubPerson();
// sp1.setGender("女");
// 第二種默認是String 泛型
// SubPerson sp2 = new SubPerson();
// sp1.setGender("女");
// 第三種 可以指定類型依次從子=》父
// SubPerson<String> sp3 = new SubPerson<String>();
// sp1.setGender("女");
// 第四種 指定了父子 類型
SubPerson<String, Boolean> sp4 = new SubPerson<>();
sp4.setGender("女");
}
}
~~~
>[info] ## 自定義泛型方法
1. 泛型方法就是我們輸入參數的時候,輸入的是泛型參數,而不是具體的參數。我們在調用這個泛型方法的時需要對泛型參數進行實例化
2. 泛型方法的格式:`[訪問權限] <泛型> 返回值類型 方法名([泛型標識 參數名稱]) { 方法體; }`
~~~
public class PersonTest<T> {
private T name;
// 不屬于泛型方法
public T getName() {
return name;
}
// 不屬于泛型方法
public void setName(T name) {
this.name = name;
}
// 定義一個泛型方法,打印任意類型數組中每一個值
public <E> void getArrayItem(E[] arr) {
for (E item : arr) {
System.out.println(item);
}
}
// 定義一個泛型方法,返回原數組
public <E> E[] getArray(E[] arr) {
return arr;
}
// 定義一個靜態泛型方法
public static <E> E[] getSArray(E[] arr) {
return arr;
}
public static void main(String[] args) {
PersonTest<String> pt = new PersonTest<>();
Integer[] arr = { 1, 2, 3, 4, 5, 6 };
// int[] arr = { 1, 2, 3, 4, 5, 6 }; // 泛型不能是基本類型 否則報錯
Integer[] getLs = pt.getArray(arr);
pt.getArrayItem(arr);
PersonTest.getSArray(arr);
}
}
~~~
>[info] ## 通配符的使用
1. `<?>` 無限制通配符:表示我們可以傳入任意類型的參數,但任意類型集合是不能進行添加操作,任意類型可以接受其他泛型集合,可進行獲取操作(獲取是Object)
~~~
// 1.聲明兩個List類型的集合進行測試
List<Animal> lt1 = new LinkedList<>();
List<Dog> lt2 = new LinkedList<>();
// 試圖將lt2的數值賦值給lt1,也就是發生List<Dog>類型向List<Animal>類型的轉換
//lt1 = lt2; Error: 類型之間不具備父子類關系
System.out.println("---------------------------------------------");
// 2.使用通配符作為泛型類型的公共父類
List<?> lt3 = new LinkedList<>();
lt3 = lt1; // 可以發生List<Animal>類型到List<?>類型的轉換
lt3 = lt2; // 可以發生List<Dog>類型到List<?>類型的轉換
// 向公共父類中添加元素和獲取元素
//lt3.add(new Animal()); Error: 不能存放Animal類型的對象
//lt3.add(new Dog()); Error: 不能存放Dog類型的對象, 不支持元素的添加操作
Object o = lt3.get(0); // ok,支持元素的獲取操作,全部當做Object類型來處理
~~~
2. `<? extends E>` 表示類型的上界是E,只能是E或者是E的子類,集合類型不支持元素的添加操作,可進行獲取操作(獲取是E類型)
~~~
// 3.使用有限制的通配符進行使用
List<? extends Animal> lt4 = new LinkedList<>();
// 不支持元素的添加操作
//lt4.add(new Animal());
//lt4.add(new Dog());
//lt4.add(new Object());
// 獲取元素
Animal animal = lt4.get(0);
~~~
3. `<? super E>` 表示類型的下界是E,只能是E或者是E的父類。(獲取是Object)
~~~
List<? super Animal> lt5 = new LinkedList<>();
lt5.add(new Animal());
lt5.add(new Dog());
//lt5.add(new Object()); Error: 超過了Animal類型的范圍
Object object = lt5.get(0);
~~~
- windows -- 環境變量
- Vscode -- 編寫java
- 初始java
- java -- 關鍵字
- 編寫第一個java程序
- java -- 注釋
- 計算機存儲 -- 進制
- java -- 類型
- java -- 變量
- 數字類型
- 布爾類型
- 字符類型
- 類型轉換
- 雙等比較是什么
- java -- 運算符
- 算數運算符
- 字符串拼接
- 關系/比較運算符
- 自增減運算符
- 邏輯運算符
- 三目運算
- 賦值運算符
- 移位運算符
- 位運算符
- 運算符優先級
- java -- 流程控制語句
- if /else if /if -- 判斷
- switch case分支結構
- for -- 循環
- 用雙重for循環
- while -- 循環
- do while -- 循環
- 案例練習
- java -- 數組
- 數組的存儲
- 數組的增刪改查
- 數組的特點
- 數組案例
- 二維數組
- 數組的工具方法
- java -- 方法
- java -- 方法的重載
- java -- 方法的調用流程
- java -- 類方法傳參注意事項
- java -- 方法練習案例
- 對比 return break continue
- for each循環
- java -- 基礎練習
- java -- 面向對象
- java -- 創建類和對象
- java -- 訪問控制符
- java -- 類成員方法
- java -- 構造方法
- java -- this
- java -- 封裝
- java -- 對象內存圖
- java -- 創建對象案例
- java -- static
- java -- 繼承
- super -- 關鍵字
- java -- 構造塊和靜態代碼塊
- java -- 重寫
- java -- final
- java -- 多態
- java -- 抽象類
- java -- 接口
- 引用類型數據轉換
- 綜合案例
- java -- 內部類
- java -- 回調模式
- java -- 枚舉類型
- java -- switch 使用枚舉
- java -- 枚舉方法使用
- java -- 枚舉類實現接口
- java -- javaBean
- java -- package 包
- java -- import
- java -- 遞歸練習
- java -- 設計模式
- 單例模式
- java -- 注解
- java -- 元注解
- Java -- 核心類庫
- java -- 處理字符串
- Java -- String
- String -- 常用方法
- String -- 正則
- Java -- StringBuilder 和 StringBuffer
- 知識點
- Java -- StringJoiner 字符串拼接
- 練習題
- 字符串的總結
- Java -- 包裝類
- Integer
- Double
- Boolean
- Character
- java -- 集合類
- java -- util.Collection
- Iterator接口
- java -- util.List
- java -- ArrayList
- java -- util.Queue
- java -- util.Set
- java -- util.Map
- java -- util.Collections
- Java -- Math
- Java -- java.lang
- Java -- Object
- Java -- 獲取當前時間戳
- Java -- 異常
- Java -- java.util
- java -- Date
- java -- Calender
- Java -- java.text
- Java -- SimpleDateFormat
- Java -- java.time
- Java -- java.io
- java -- io.File
- java -- 泛型
- IDEA -- 用法