1. 程式人生 > 遊戲攻略 >《小緹娜的奇幻之地》閃蹄城收集指南 閃蹄城收集品在哪

《小緹娜的奇幻之地》閃蹄城收集指南 閃蹄城收集品在哪

泛型

一、泛型引入

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;
    }
}

使用傳統方法的問題分析

  1. 不能對加入到集合ArrayList中的資料型別進行約束(不安全
  2. 遍歷的時候,需要進行型別轉換,如果集合中的資料量較大,對效率有影響

二、泛型入門

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;
    }
}
  1. 當我們 ArrayList 表示存放到ArrayList 集合中的元素是Dog型別
  2. 如果編譯器發現新增的型別,不滿足要求,就會報錯
  3. 在遍歷的時候,可以直接取出 Dog 型別,而不是Object型別

小結:

  • 編譯時,檢查新增元素的型別,提高了安全性
  • 減少了型別轉換的次數,提高效率
  • 不再提示編譯警告

不使用泛型

Dog -加入-> Object -取出 -> Dog//放到ArrayList中會先轉成Object,在取出時,還需要轉成Dog

使用泛型

Dog -> Dog -> Dog//放入和取出時,不需要進行型別的轉換,提高效率


三、泛型介紹

老韓理解:泛(廣泛)型(型別)=> Integer, String,Dog

  • 即可以表示其他資料的型別的資料型別
  1. 泛型又稱引數化型別,是Jdk5.0出現的新特性,解決資料型別的安全性問題

  2. 在類宣告或例項化時只要指定好需要的具體的型別即可。

  3. Java泛型可以保證如果程式在編譯時沒有發出警告,執行時就不會產生,ClassCastException異常。同時,程式碼更加簡潔、健壯

  4. 泛型的作用是:可以在類宣告時通過一個標識表示類中某個屬性的型別,或者是某個方法的返回值的型別,或者是引數型別。[有點難,舉例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 介面{} 和 class <K,V>{}

比如:List,ArrayList

說明:

  1. 其中,T,K,V不代表值,而是表示型別
  2. 任意字母都可以。 常用T表示(Type)

泛型的例項化

  1. List strList = new ArrayList();
  2. 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;

五、泛型語法和使用

  1. interface List{}, public class HashSet{}..等等

    • 這裡的E,T...等等只能是引用型別
    • 即給泛型指定型別的時候,只能是引用型別,不能是基本資料型別
    List<Integer> list = new ArrayList<Integer>();//OK
    List<int> list = new ArrayList<int>();//只能是引用型別
    
  2. 在給泛型指定了的具體型別後,可以傳入該型別的子型別或者改型別

  3. 泛型使用形式

    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...>{//可以有多個
    成員
}

注意細節:

  1. 普通成員可以使用泛型(屬性、方法)
  2. 使用泛型的陣列,不能初始化
  3. 靜態方法中不能使用類的泛型
  4. 泛型類的型別,是在建立物件時確定的(因為建立物件時,需要指定確定型別)
  5. 如果在建立物件時,沒有指定型別,預設為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;
    }
}
  1. Tiger後面有泛型,所有我們把Tiger就稱為 自定義泛型類
  2. T,R,M為泛型的識別符號,一般是單個大寫字母
  3. 泛型識別符號可以有多個

自定義泛型介面

基本語法

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;
    }

}

注意細節:

  1. 介面中,靜態成員也不能使用泛型(這個和泛型類規定一樣)
    • 在介面中的屬性都是靜態的,公開的,finale的
  2. 泛型介面的型別,在繼承介面或者實現介面時確定
  3. 沒有指定型別,預設為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());//
    }

}

注意細節:

  1. 泛型方法,可以定義在普通類中,也可以定義在泛型類中
  2. 當泛型方法被呼叫時,型別會確定
  3. public void eat(Ee){},修飾符後沒有<T,R..>,eat方法不是泛型方法,而是使用了泛型
  4. 泛型方法,可以使用類宣告的泛型,也可以使用自己宣告的泛型

七、泛型的繼承和萬用字元

  1. 泛型不具備繼承性

    List<Object> list = new ArrayList<String>();//不正確
    
  2. :支援任意泛型型別
  3. :**支援A類以及A類的子類,規定了泛型的上限**
  4. :**支援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 + '\'' +
                '}';
    }
}