《小緹娜的奇幻之地》閃蹄城收集指南 閃蹄城收集品在哪
阿新 • • 發佈:2022-04-07
泛型
一、泛型引入
package com.hspedu.generic; import java.util.ArrayList; /** * @author DL5O * @version 1.0 */ @SuppressWarnings("all") public class Generic01 { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add(new Dog("旺財",5)); list.add(new Dog("發財",1)); list.add(new Dog("小黃",6)); list.add(new Cat("招財貓",8));//加入一隻貓 //遍歷 for (Object o :list) { Dog dog = (Dog)o;//向下轉型 System.out.println("name=" + dog.getName() + ",age=" + dog.getAge()); } } } class Dog{ private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } class Cat{ private String name; private int age; public Cat(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
使用傳統方法的問題分析
- 不能對加入到集合ArrayList中的資料型別進行約束(不安全)
- 遍歷的時候,需要進行型別轉換,如果集合中的資料量較大,對效率有影響
二、泛型入門
package com.hspedu.generic.improve; import java.util.ArrayList; /** * @author DL5O * @version 1.0 */ @SuppressWarnings("all") public class Generic02 { public static void main(String[] args) { //引入泛型 //傳統方法解決 ===> 使用泛型 //1.當我們 ArrayList<Dog> 表示存放到ArrayList 集合中的元素是Dog型別 //2.如果編譯器發現新增的型別,不滿足要求,就會報錯 //3.在遍歷的時候,可以直接取出 Dog 型別,而不是Object型別 ArrayList<Dog> list = new ArrayList<Dog>(); list.add(new Dog("旺財",5)); list.add(new Dog("發財",1)); list.add(new Dog("小黃",6)); // list.add(new Cat("招財貓",8));//加入一隻貓,使用泛型後,就加入不了了 System.out.println("===使用泛型==="); for (Dog dog :list) { System.out.println("name=" + dog.getName() + ",age=" + dog.getAge()); } } } class Dog{ private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } class Cat{ private String name; private int age; public Cat(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } }
- 當我們 ArrayList
表示存放到ArrayList 集合中的元素是Dog型別 - 如果編譯器發現新增的型別,不滿足要求,就會報錯
- 在遍歷的時候,可以直接取出 Dog 型別,而不是Object型別
小結:
- 編譯時,檢查新增元素的型別,提高了安全性
- 減少了型別轉換的次數,提高效率
- 不再提示編譯警告
不使用泛型
Dog -加入-> Object -取出 -> Dog//放到ArrayList中會先轉成Object,在取出時,還需要轉成Dog
使用泛型
Dog -> Dog -> Dog//放入和取出時,不需要進行型別的轉換,提高效率
三、泛型介紹
老韓理解:泛(廣泛)型(型別)=> Integer, String,Dog
- 即可以表示其他資料的型別的資料型別
-
泛型又稱引數化型別,是Jdk5.0出現的新特性,解決資料型別的安全性問題
-
在類宣告或例項化時只要指定好需要的具體的型別即可。
-
Java泛型可以保證如果程式在編譯時沒有發出警告,執行時就不會產生,
ClassCastException
異常。同時,程式碼更加簡潔、健壯 -
泛型的作用是:可以在類宣告時通過一個標識表示類中某個屬性的型別,或者是某個方法的返回值的型別,或者是引數型別。[有點難,舉例Generic03.java]
注意:(特別強調!!!)
- E的資料型別在定義的Person的時候指定,即在編譯期間,就確定E是什麼型別
package com.hspedu.generic;
/**
* @author DL5O
* @version 1.0
*/
public class Generic03 {
public static void main(String[] args) {
Person<String> ywl = new Person<>("ywl");
ywl.show();//String
/*
可以這樣理解,上面的Person類
把E 替換成了String,可以這樣理解,但這樣不太準確
*/
Person<Integer> integerPerson = new Person<>(100);
//E 這個泛型在定義的時候就知道了
integerPerson.show();//Interger
}
}
//泛型的作用:可以在類宣告時通過一個標識表示類中某個屬性的型別,
// 或者是某個方法的返回值的型別,或者是引數型別。
class Person<E>{
E s;
//E表示 s的資料型別,該資料型別是在定義Person物件的時候指定的,
// 即在編譯期間就確定了E是什麼型別了
public Person(E s) {//E也可以是引數型別中體現
this.s = s;
}
public E f(){//返回型別使用E
return s;
}
public void show(){
System.out.println(s.getClass());//輸出顯示S的執行型別
}
}
四、泛型的語法
interface 介面
比如:List,ArrayList
說明:
- 其中,T,K,V不代表值,而是表示型別
- 任意字母都可以。 常用T表示(Type)
泛型的例項化
- List
strList = new ArrayList (); - Iterator
iterator = customers.iterator();
package com.hspedu.generic;
import java.util.*;
/**
* @author DL5O
* @version 1.0
*/
public class GenericExercise {
public static void main(String[] args) {
Student ywl = new Student("ywl", 21);
Student zsj = new Student("zsj", 20);
Student sky = new Student("sky", 19);
//HashMap 遍歷方式
// System.out.println("====HashMap遍歷方式====");
HashMap<String, Student> map = new HashMap<String, Student>();
/*
public class HashMap<K,V>
*/
map.put("ywl", ywl);
map.put("zsj", zsj);
map.put("sky", sky);
System.out.println("====keySet====");
//迭代器 EntrySet
Set<Map.Entry<String, Student>> entries = map.entrySet();
/*
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
*/
Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();
while (iterator1.hasNext()) {
Map.Entry<String, Student> student = iterator1.next();
System.out.println(student.getKey() + "-" + student.getValue());
}
//HashSet
System.out.println("====HashSet====");
HashSet<Student> students = new HashSet<>();
students.add(ywl);
students.add(zsj);
students.add(sky);
//迭代器遍歷
Iterator<Student> iterator = students.iterator();
while (iterator.hasNext()) {
Student student = iterator.next();
System.out.println(student);
}
System.out.println("====增強for迴圈====");
//for迴圈遍歷
for (Student student : students) {
System.out.println(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 "姓名:" + name + ",年齡:" + age;
}
}
注意:
- 定義
HashMap
的時候,已經把key和value指定了,而迭代器中的k,v也能跟著確定下來,故存進去的都是<String,Student> 的鍵值對,取出來的也是這樣的一對鍵值對- 然後使用getValue方法可以獲得Student物件,getKey可以獲得鍵值
- K-> String,Value-> Student;
五、泛型語法和使用
-
interface List
{}, public class HashSet {}..等等 - 這裡的E,T...等等只能是引用型別
- 即給泛型指定型別的時候,只能是引用型別,不能是基本資料型別
List<Integer> list = new ArrayList<Integer>();//OK List<int> list = new ArrayList<int>();//只能是引用型別
-
在給泛型指定了的具體型別後,可以傳入該型別的子型別或者改型別
-
泛型使用形式
List<Interger> list = new ArrayList<>();//推薦寫法 List<Interger> list = new ArrayList<Interger>();
- 如果這樣寫
List list = new ArrayList();
他的預設泛型是Object;- 它等價於:
List<Object> list = new ArrayList<>();
- 它等價於:
- 如果這樣寫
課堂練習題
package com.hspedu.generic.exercise;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
/**
* @author DL5O
* @version 1.0
*/
public class GenericExercise01 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("小龍23", 5000, new MyDate(2000, 9, 9)));
employees.add(new Employee("大龍23", 6000, new MyDate(2001, 10, 9)));
employees.add(new Employee("小張", 7500, new MyDate(2002, 11, 9)));
employees.add(new Employee("小宋", 6500, new MyDate(2001, 5, 9)));
System.out.println("====排序前====");
for (Employee e : employees) {
System.out.println(e);
System.out.println();
}
System.out.println("====進行排序====");
//進行排序操作
//按照name進行排序,如果name相同,就按照生日的先後順序進行排序
Collections.sort(employees, new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
// int ret = e1.getName().compareTo(e2.getName());
int ret = e1.getName().length() - e2.getName().length();
//長度也按從小到大來比較
if (ret != 0) {
return ret;
}
//如果名字/名字長度相同
//出生年月按從大到下進行比較
//下面是對birthday的比較,因此,我們最好把這個比較,放在MyDate類完成
//封裝後,將來可維護性和複用性,就大大增強
MyDate e1Birthday = e1.getBirthday();
MyDate e2Birthday = e2.getBirthday();
return e1Birthday.compareTo(e2Birthday);
}
});
Iterator<Employee> iterator = employees.iterator();
while (iterator.hasNext()) {
Employee e = iterator.next();
System.out.println(e);
System.out.println();
}
}
/*//對ArrayList 集合中的元素進行排序
public static void sort(ArrayList<Employee> employees){
}*/
}
class Employee {
private String name;
private double sal;
private MyDate birthday;
public Employee(String name, double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "姓名:" + name + "\n工資:" + sal + "\n出生日期:" + birthday;
}
}
class MyDate implements Comparable<MyDate> {
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
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 year + "." + month + "." + day;
}
@Override
public int compareTo(MyDate o) {//把對年月日year-month-day的比較放在這裡
/*if (year > o.getYear()) {
return 1;
} else if (month > o.getMonth()) {
return 1;
} else if (day > o.getDay()) {
return 1;
} else if (year < o.getYear()
|| month < o.getMonth() ||
day < o.getDay()) {
return -1;
} else {
return 0;
}*/
//老師的思路
//如果出生年份不一樣
int yearMinus = year - o.getYear();
if (yearMinus != 0) {
return yearMinus;
}
//如果出生年份一樣,但月份不一樣
int monthMinus = month - o.getMonth();
if (monthMinus != 0) {
return monthMinus;
}
//如果出生年份月份一樣,就比較日期
int dayMinus = day - o.getDay();
return dayMinus;
}
}
六、自定義泛型
自定義泛型類
基本語法:
class 類名<T,R...>{//可以有多個
成員
}
注意細節:
- 普通成員可以使用泛型(屬性、方法)
- 使用泛型的陣列,不能初始化
- 靜態方法中不能使用類的泛型
- 泛型類的型別,是在建立物件時確定的(因為建立物件時,需要指定確定型別)
- 如果在建立物件時,沒有指定型別,預設為
Object
應用案例:
package com.hspedu.generic.cusotmgeneric;
/**
* @author DL5O
* @version 1.0
*/
public class CustomGeneric {
public static void main(String[] args) {
}
}
//解讀
//1.Tiger後面有泛型,所有我們把Tiger就稱為 自定義泛型類
//2.T,R,M泛型識別符號,一般那都是字母大寫
//3.泛型可以有多個
//4.普通成員,屬性,方法都可以使用泛型
class Tiger<T,R,M>{
String name;
R r; //屬性
M m;
T t;
//因為陣列在new 的時候,不能確定T的型別,就無法在記憶體中開空間
T [] ts;//使用泛型的不允許直接初始化
public Tiger(String name){
this.name = name;
}
public Tiger(String name, R r, M m, T t) {
this.name = name;
this.r = r;
this.m = m;
this.t = t;
}
//在載入tiger類的時候,M泛型仍然不確定是怎麼樣的型別
//因為是靜態的和類相關的,在類載入時,物件可能還沒有建立
//所有靜態方法和靜態屬性使用了泛型,JVM 就無法完成初始化
/* static R r2;
public static void m1(M m){
}*/
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
- Tiger後面有泛型,所有我們把Tiger就稱為 自定義泛型類
-
T,R,M為
泛型的識別符號,一般是單個大寫字母 - 泛型識別符號可以有多個
自定義泛型介面
基本語法
interface 介面名<T,R...>{
}
package com.hspedu.generic.cusotmgeneric;
/**
* @author DL5O
* @version 1.0
*/
public class CustomInterfaceGeneric {
public static void main(String[] args) {
}
}
/**
* 泛型介面的注意事項和說明
* 1.介面中,靜態成員也不能使用泛型(這個和泛型類規定一樣)
*/
//在繼承介面 指定泛型介面的型別
interface IA extends IUsb<String,Double>{
}
//當我們去實現IA 介面時,因為IA 在繼承IUsb時指定了泛型的型別
// U:String, R:Double
//在實現IUsb介面的方法時,使用String 替換U,使用Double替換R
class AA implements IA{
@Override
public Double get(String s) {
return null;
}
@Override
public void hi(Double aDouble) {
}
@Override
public void run(Double r1, Double r2, String u1, String u2) {
}
}
//實現介面時,直接指定泛型介面
//給U指定了Integer ,給R指定了Float
//所以,當我們實現IUsb方法時,會使用Integer替換U,使用Float替換R
class BB implements IUsb<Integer,Float>{
@Override
public Float get(Integer integer) {
return null;
}
@Override
public void hi(Float aFloat) {
}
@Override
public void run(Float r1, Float r2, Integer u1, Integer u2) {
}
}
//沒有指定型別,預設為Object
//Object 會替換 U,R
class CC implements IUsb<Object,Object>{
@Override
public Object get(Object o) {
return null;
}
@Override
public void hi(Object o) {
}
@Override
public void run(Object r1, Object r2, Object u1, Object u2) {
}
}
interface IUsb<U,R>{
int n = 10;
//U name =""; 不能使用
//在普通方法中,可以使用泛型介面
R get(U u);
void hi(R r);
void run(R r1, R r2 , U u1, U u2);
//在jdk8.0中,可以在介面中,使用預設方法,也是可以使用泛型的
default R method(U u){
return null;
}
}
注意細節:
- 介面中,靜態成員也不能使用泛型(這個和泛型類規定一樣)
- 在介面中的屬性都是靜態的,公開的,finale的
- 泛型介面的型別,在繼承介面或者實現介面時確定
- 沒有指定型別,預設為Object
自定義泛型方法
基本語法
修飾符 <T,R..>返回型別 方法名(引數列表){
}
package com.hspedu.generic.cusotmgeneric;
import java.util.ArrayList;
/**
* @author DL5O
* @version 1.0
*/
public class CustomGenericMethodGeneric {
public static void main(String[] args) {
Car car = new Car();
car.fly("你好", 10);//這裡的是10會進行自動裝箱
//當呼叫方法時,傳入引數,編譯器,就會確定型別
System.out.println("=============");
car.fly(300, 10.3);
System.out.println("=============");
//T->String R->ArrayList
Fish<String, ArrayList> fish = new Fish<>();
fish.hello(new ArrayList(),11.3f);
}
}
//泛型方法,可以定義在普通類中,也可以定義在泛型類中
class Car {//非常普通的類
public void run() {//普通方法
}
//解讀
//1.<T,R> 為泛型識別符號
//2.提供給 fly 使用的
public <T, R> void fly(T t, R r) {//泛型方法
System.out.println(t.getClass());//String
System.out.println(r.getClass());//Integer
}
}
class Fish<T, R> {//泛型類
public void run() {
}
public <U, M> void eat(U u, M m) {//泛型方法
}
//說明
//1.下面hi方法不是泛型方法
//2.是hi方法使用了類宣告的泛型 T
public void hi(T t) {
}
//泛型方法,可以使用類宣告的泛型,也可以使用自己宣告的泛型
public <K> void hello(R r,K k) {
System.out.println(r.getClass());//ArrayList
System.out.println(k.getClass());//
}
}
注意細節:
- 泛型方法,可以定義在普通類中,也可以定義在泛型類中
- 當泛型方法被呼叫時,型別會確定
-
public void eat(Ee){},
修飾符後沒有<T,R..>,eat方法不是泛型方法,而是使用了泛型 - 泛型方法,可以使用類宣告的泛型,也可以使用自己宣告的泛型
七、泛型的繼承和萬用字元
-
泛型不具備繼承性
List<Object> list = new ArrayList<String>();//不正確
- :支援任意泛型型別
- :**支援A類以及A類的子類,規定了泛型的上限**
- :**支援A類以及A類的父類,不限於直接父類,規定了泛型的下限**
package com.hspedu.generic;
import java.util.ArrayList;
import java.util.List;
/**
* @author DL5O
* @version 1.0
* 泛型的繼承的萬用字元
*/
public class GenericExtends {
public static void main(String[] args) {
Object xx = new String("xx");
//泛型沒有繼承性
// List<Object> list = new ArrayList<String>();//不正確
//舉例說明下面三個方法的使用
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<AA> list3 = new ArrayList<>();
List<BB> list4 = new ArrayList<>();
List<CC> list5 = new ArrayList<>();
//如果是List<?> 可以接受任意的泛型型別
printCollection1(list1);
printCollection1(list2);
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
//如果是printCollection2 List<? extends AA>
// printCollection2(list1); 語法通不過Object 不是 AA的子類
// printCollection2(list2); 語法通不過String 不是 AA的子類
printCollection2(list3);
printCollection2(list4);
printCollection2(list5);
//printCollection3(List<? super AA> c)
//接受AA 和它的父類,不限於直接父類
printCollection3(list1);
// printCollection3(list2); String 和AA 沒有任何關係
printCollection3(list3);
// printCollection3(list4); BB 為 AA 的子類
// printCollection3(list5); CC 為 AA 的子類
}
//說明: List<?> 表示任意的泛型型別都可以接收
public static void printCollection1(List<?> c) {
for (Object object : c) {
System.out.println(object);
}
}
//List<? extends AA> 表示上限,可以接受AA 或 AA的子類
public static void printCollection2(List<? extends AA> c) {
for (Object object : c) {
System.out.println(object);
}
}
//List<? super AA> 子類名AA : 支援AA類以及AA類的父類,不限於直接父類
//規定了泛型的下限
public static void printCollection3(List<? super AA> c) {
for (Object object : c) {
System.out.println(object);
}
}
}
class AA {
}
class BB extends AA {
}
class CC extends BB {
}
本章作業
Homework01
package com.hspedu.generic.Homewrok;
import java.util.*;
/**
* @author DL5O
* @version 1.0
*/
public class Homework01 {
public static void main(String[] args) {
User ywl = new User(1, 21, "ywl");
User sky = new User(2, 20, "sky");
User zsj = new User(3, 19, "zsj");
User wjq = new User(4, 18, "wjq");
User py = new User(4, 20, "py");
//sava方法的使用
DAO<User> userDAO = new DAO<>();
userDAO.save("1", ywl);
userDAO.save("2", sky);
userDAO.save("3", zsj);
userDAO.save("4", wjq);
System.out.println("====新增之後====");
//list方法的使用
List<User> list = userDAO.list();
DAO.output(list);
System.out.println("=====修改之後====");
//update函式的使用
userDAO.update("4", py);
DAO.output(list);
System.out.println("====1號ID使用者的資訊====");
System.out.println(userDAO.get("1"));
System.out.println("====刪除之後====");
userDAO.delete("1");
list = userDAO.list();
DAO.output(list);
}
}
DAO
package com.hspedu.generic.Homewrok;
import java.util.*;
/**
* @author DL5O
* @version 1.0
*/
public class DAO<T>{
private Map<String,T> map = new HashMap<>();
//儲存t物件到Map 成員變數中
public void save(String id,T entity){
map.put(id,entity);
}
//獲取id對應的物件
public T get(String id){
return map.get(id);
}
//替換map中的key為id的內容,改為entity物件
public void update(String id,T entity){
map.replace(id,entity);
// map.put(id,entity);
}
//返回map中存放的所有t物件
public List<T> list(){
//建立ArrayList
List<T> list = new ArrayList<>();
//第一種
/*Set<String> keySet = map.keySet();
for (String key: keySet) {
list.add(map.get(key));
}*/
//第二種
Collection<T> values = map.values();
Iterator<T> iterator = values.iterator();
while (iterator.hasNext()) {
T t = iterator.next();
list.add(t);
}
return list;
}
/*public Collection<T> list(){
return map.values();
}*/
//刪除指定的id物件
public void delete(String id){
map.remove(id);
}
//輸出
public static void output(List<User> list) {
Iterator<User> iterator = list.iterator();
while (iterator.hasNext()) {
User user = iterator.next();
System.out.println(user);
}
}
}
User
package com.hspedu.generic.Homewrok;
/**
* @author DL5O
* @version 1.0
*/
public class User {
private int id;
private int age;
private String name;
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}