目錄
一、泛型的介紹
- 泛型又稱參數化類型,是Jdk5.0 出現的新特性,解決數據類型的安全性問題
- 在類聲明或實例化時只要指定好需要的具體的類型即可。
- Java泛型可以保證如果程序在編譯時沒有發出警告,運行時就不會產生ClassCastException異常。同時,代碼更加簡潔、健壯
- 在類聲明時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。
二、泛型的語法
2.1 泛型的聲明
interface List<T> 和 class GenTest<K,V>
說明:
- 其中,T,K,V不代表值,而是表示類型。這裏使
- 用任意字母都可以。常用T表示,是Type的縮寫
2.2 泛型的實例化:
要在類名後面指定類型參數的值(類型)。如:
1) List<String> strList = new ArrayList<String>();
- 1. new ArrayList<String> 仍然是運行類型, 表示ArrayList ,並且只能存放String類型
- 2. List<String> 仍然是編譯類型, 表示是一個List類型,可以存放String類型
2) Iterator<Customer> iterator = customers.iterator();
- 返回迭代器時,直接指定迭代器指向就是此類型
2.3 泛型使用舉例
舉例說明,泛型在 HashSet, TreeSet, HashMap 的使用情況, 看老師演示
import java.util.HashMap; import java.util.HashSet; import java.util.Set;
public class GenericDemo03 { public static void main(String[] args) { // TODO Auto-generated method stub // 舉例說明,泛型在 HashSet, TreeSet, HashMap 的使用情況, 看老師演示
HashSet<Student> hashSet = new HashSet<Student>(); Student student1 = new Student("jack", 1); Student student2 = new Student("tom", 10); Student student3 = new Student("smith", 4); hashSet.add(student1); hashSet.add(student2); hashSet.add(student3);
//遍歷 for (Student student : hashSet) { System.out.println(student); }
// 雙列集合 //public class HashMap<K,V>{} //傳入幾個類型 HashMap<String, Student> hashMap = new HashMap<String, Student>(); hashMap.put("100", student1); hashMap.put("200", student2); hashMap.put("300", student3);
//遍歷 Set<String> keySet = hashMap.keySet(); for (String key : keySet) { Student student = hashMap.get(key); System.out.println("s=" + student); } }
}
class Student { public String name; public int age;
public Student(String name, int age) { super(); this.name = name; this.age = age; }
@Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; }
}
|
2.3 泛型使用的注意事項和細節
1) interface List<T> ,public class HashSet<E>.. 等等
說明:T, E 只能是引用類型
看看下面語句是否正確?:
List<Integer> list = new ArrayList<Integer>();//T
List<int> list2 = new ArrayList<int>();//F, 泛型不能是基本數據類型
2) 泛型使用的形式
List<Integer> list4 = new ArrayList<Integer>();
List<Integer> list4 = new ArrayList<>(); [說明: 會根據前面的編譯類型的泛型,來推斷<>中是什麼類型] , 推薦使用
2.4 泛型課堂練習題
定義Employee類
1) 該類包含:private成員變量name,age,birthday,其中 birthday 爲 MyDate 類的對象;
2) 爲每一個屬性定義 getter, setter 方法;
3) 重寫 toString 方法輸出 name, age, birthday
4) MyDate類包含: private成員變量month,day,year;併爲每一個屬性定義 getter, setter 方法;
5) 創建該類的 3 個對象,並把這些對象放入 ArrayList 集合中(ArrayList 需使用泛型來定義),並遍歷輸出(選擇一個即可):
排序方式: 調用ArrayList 的 sort 方法, 傳入 Comparator對象,先按照name,排序,如果name相同,則按生日日期的先後排序。【即:定製排序】
代碼演示
package com.atguigu.generic;
import java.util.ArrayList; import java.util.Comparator; import java.util.Iterator;
public class GenericExercise01 {
public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<Employee> arrayList = new ArrayList<>(); MyDate myDate1 = new MyDate(2000,11,11); MyDate myDate2 = new MyDate(2000,11,10); MyDate myDate3 = new MyDate(2000,11,1);
Employee employee1 = new Employee("jack", 10, myDate1); Employee employee2 = new Employee("jack", 20, myDate2); Employee employee3 = new Employee("jack", 30, myDate3);
arrayList.add(employee1); arrayList.add(employee2); arrayList.add(employee3);
//迭代器 Iterator<Employee> iterator = arrayList.iterator(); while(iterator.hasNext()) { Employee employee = iterator.next(); System.out.println(employee); }
//定製排序. arrayList.sort(new Comparator<Employee>() {
@Override public int compare(Employee o1, Employee o2) { //先看名字 int compareTo1 = o1.getName().compareTo(o2.getName()); if(compareTo1 !=0) {//比較有結果 return compareTo1; } else { //比較 生日. return o1.getBirthday().compareTo(o2.getBirthday()); } } }); System.out.println("排序=" + arrayList);
}
} /* * 定義Employee類 1) 該類包含:private成員變量name,age,birthday,其中 birthday 爲 MyDate 類的對象; 2) 爲每一個屬性定義 getter, setter 方法; 3) 重寫 toString 方法輸出 name, age, birthday 4) MyDate類包含: private成員變量month,day,year;併爲每一個屬性定義 getter, setter 方法; 5) 創建該類的 3 個對象,並把這些對象放入 ArrayList 集合中(ArrayList 需使用泛型來定義),並遍歷輸出(選擇一個即可): 排序方式: 調用ArrayList 的 sort 方法, 傳入 Comparator對象, 先按照name,排序,如果name相同,則按生日日期的先後排序。【即:定製排序】
*/ class Employee { private String name; private int age; private MyDate birthday; public Employee(String name, int age, MyDate birthday) { super(); this.name = name; this.age = age; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public MyDate getBirthday() { return birthday; } public void setBirthday(MyDate birthday) { this.birthday = birthday; } @Override public String toString() { return "Employee [name=" + name + ", age=" + age + ", birthday=" + birthday + "]\n"; }
}
class MyDate implements Comparable<MyDate>{ private int year; private int month; private int day; public MyDate(int year, int month, int day) { super(); this.year = year; this.month = month; this.day = day; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } @Override public String toString() { return "MyDate [year=" + year + ", month=" + month + ", day=" + day + "]"; } @Override public int compareTo(MyDate o) { //想到... //比較年 int compare1 = year - o.year; if(compare1 != 0) { return compare1; } else { //比較月 int compare2 = month - o.month; if(compare2 != 0) { return compare2; } else { return day - o.day; } } }
} |
2.5 自定義泛型類
- 基本語法
class 類名<T, R...> {
成員
}
注意細節
1) 普通成員可以使用泛型
2) 使用泛型的數組,不能初始化
3) 靜態成員中不能使用泛型
4) 泛型類的類型,是在創建對象時確定的(因爲創建對象時,需要指定確定類型)
5) 如果在創建對象時,沒有指定類型,默認爲Object
- 應用案例
下面舉例說明自定義泛型的使用, 看老師演示.
package com.atguigu.generic;
public class CustomGeneric {
public static void main(String[] args) {
//使用自定義泛型 //解讀 //1. 當創建對象時, T 就是 String // R 就是 Integer // M 就是 Double MyGeneric<String, Integer, Double> myGeneric = new MyGeneric<>("尚硅谷");
//變化 myGeneric.setM(100.3); myGeneric.setR(100); myGeneric.setT("hello");
System.out.println(myGeneric.getT());
// T 就是 Book // R 就是 Float // M 就是 String MyGeneric<Book, Float, String> myGeneric2 = new MyGeneric<>("尚硅谷");
//如果在創建對象時,沒有指定類型,默認爲Object MyGeneric<Object,Object,Object> myGeneric3 = new MyGeneric("hsp");
}
}
class Book {
}
//自定義的泛型 class MyGeneric<T, R, M> { String name; R r; // 普通成員屬性,可以使用泛型
// 普通成員方法,可以使用泛型 public R getR() { return r; }
public void setR(R r) { this.r = r; }
public M getM() { return m; }
public void setM(M m) { this.m = m; }
M m; T t; // 不允許泛型數組開闢長度或初始化, 因爲數組在開空間時,大小需要明確,而T 不能明確空間大小 //T[] ts = new T[9];
// 不允許靜態成員使用泛型, 因爲 靜態成員是在加載類的時候,就完成,而我們的T是在創建對象時,才確定 // 因爲,不能通過 // static T m; // public static void method(T t){ // // } public static void show() { }
public T getT() { return t; }
public void setT(T t) { this.t = t; }
@Override public String toString() { return "MyGeneric [name=" + name + "]"; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public MyGeneric(String name) { super(); this.name = name; } }
|
2.6 自定義泛型接口
- 基本語法
interface 接口名<T, R...> {
}
- 注意細節
1) 接口中,靜態成員也不能使用泛型
2) 泛型接口的類型, 在接口被擴展時(即:被繼承或者實現) 會確定
3) 沒有指定類型,默認爲Object
代碼演示
public class InterfaceGeneric { public static void main(String[] args) { // TODO Auto-generated method stub AA aa = new AA(); aa.app(1); aa.consume(12, 20, "hello", "jack"); } }
interface MyInter<T, R> { // 基於接口的泛型 // 普通方法中,可以使用接口泛型 R get(T u); void app(R r); void consume(R r1, R r2, T u1, T u2);
// 在jdk8 中,可以再接口中,使用默認方法 default R method(T u) { return null; } }
// 類與接口是實現, 傳入了類型, 使用到泛型 class AA implements MyInter<String, Integer> { @Override public Integer get(String u) { // TODO Auto-generated method stub return null; } @Override public void app(Integer r) { // TODO Auto-generated method stub } @Override public void consume(Integer r1, Integer r2, String u1, String u2) { // TODO Auto-generated method stub } }
// 接口和接口之間是繼承, 指定了類型 // 再去繼承 MyInter2時,就會體現泛型 interface MyInter2 extends MyInter<Double, Double> {
}
class BB implements MyInter2 { @Override public Double get(Double u) { // TODO Auto-generated method stub return null; } @Override public void app(Double r) { // TODO Auto-generated method stub } @Override public void consume(Double r1, Double r2, Double u1, Double u2) { // TODO Auto-generated method stub } } }
|
2.7 自定義泛型方法
- 基本語法
修飾符 <T,R..>返回類型 方法名(參數列表) {
}
- 注意細節
- 泛型方法,可以定義在普通類中, 也可以定義在泛型類中
- 當泛型方法被調用時,類型會確定.
三、泛型的繼承和通配符說明
1) 泛型不具備繼承性
2) <?> :支持任意泛型類型
3) <? extends A>:支持A類以及A類的子類,規定了泛型的上限
4) <? super A>: 支持A類以及A類的父類,不限於直接父類,規定了泛型的下限
代碼演示
package com.atguigu.generic;
import java.util.ArrayList; import java.util.List;
public class GenericPattern {
public static void main(String[] args) { // TODO Auto-generated method stub ArrayList<Object> al1 = new ArrayList<>(); ArrayList<String> al2 = new ArrayList<>(); ArrayList<AA> al3 = new ArrayList<>(); ArrayList<BB> al4 = new ArrayList<>(); ArrayList<CC> al5 = new ArrayList<>();
// 如果是 List<?> 表示都能接受. printCollection1(al3); printCollection1(al1); printCollection1(al2); printCollection1(al4); printCollection1(al5);
// List<? extends AA> 是可以接受 AA 或者 AA的子類型 // AA 是上限 . // printCollection2(al1); // printCollection2(al2); printCollection2(al3);// ok printCollection2(al4);// ok printCollection2(al5);// ok
// printCollection3(al1);// ok Object 是 AA父類 // printCollection3(al2);//error String 和AA 沒有關係 // printCollection3(al3);// ok AA // printCollection3(al4);// error BB 是AA的子類 // printCollection3(al5);// error CC 是 AA 的子類
}
// ? super 子類類名A:支持A類以及A類的父類,不限於直接父類,規定了泛型的下限 public static void printCollection3(List<? super AA> c) { for (Object object : c) { System.out.println(object); } }
// 解讀 // List<?> 表示 ? 任意的類型 引用類型 public static void printCollection1(List<?> c) { for (Object object : c) { // 通配符,取出時,就是Object System.out.println(object); } }
// ? extends AA 表示 上限,可以接受 AA或者AA子類型 public static void printCollection2(List<? extends AA> c) { for (Object object : c) { System.out.println(object); } }
}
class AA { // 超類 }
class BB extends AA {// 父類 }
class CC extends BB {// 子類 }
|