day28--Java泛型01

来源:https://www.cnblogs.com/liyuelian/archive/2022/08/29/16637287.html
-Advertisement-
Play Games

Java泛型01 1.泛型的理解和好處 看一個需求: 請編寫程式,在ArrayList中添加三個Dog對象 Dog對象含有name和age,並輸出name和age(要求使用getXXX()) 先用傳統的方法來解決 >引出泛型 傳統的方法: package li.generic; import jav ...


Java泛型01

1.泛型的理解和好處

看一個需求:

  1. 請編寫程式,在ArrayList中添加三個Dog對象
  2. Dog對象含有name和age,並輸出name和age(要求使用getXXX())

先用傳統的方法來解決--->引出泛型

傳統的方法:

package li.generic;

import java.util.ArrayList;

@SuppressWarnings("all")
public class Introduce_ {
    public static void main(String[] args) {
        
        //用傳統的方法來解決
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog("旺財",10));
        arrayList.add(new Dog("發財",1));
        arrayList.add(new Dog("小黃",5));
        
        for (Object o:arrayList) {
            //向下轉型
            Dog dog = (Dog) o;
            System.out.println(dog.getName()+"-"+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 void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
//假設,我們的程式員不小心添加了一隻貓
arrayList.add(new Cat("招財貓",8));

那麼 在使用增強for迴圈輸出的時候向下轉型時就會拋出異常:類型轉換錯誤

image-20220829152816907

使用傳統方法問題的分析:

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

使用泛型來解決問題:

package li.generic;

import java.util.ArrayList;

@SuppressWarnings("all")
public class Introduce_ {
    public static void main(String[] args) {

        //使用泛型
        // 1. 當我們這樣寫的時候:ArrayList<Dog>  表示集合ArrayList中的元素是Dog類型
        // 2. 如果編譯器發現添加的類型不滿足要求,就會報錯
        // 3.在遍歷的時候,可以直接取出Dog類型而不是Object
        ArrayList<Dog> arrayList = new ArrayList<Dog>();
        arrayList.add(new Dog("旺財",10));
        arrayList.add(new Dog("發財",1));
        arrayList.add(new Dog("小黃",5));

        //假設,我們的程式員不小心添加了一隻貓,就會報錯
        // arrayList.add(new Cat("招財貓",8));

        System.out.println("====使用泛型====");
        for (Dog dog:arrayList) {
            System.out.println(dog.getName()+"-"+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 void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = 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 void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
package li.generic;

import java.util.ArrayList;

@SuppressWarnings("all")
public class Introduce_ {
    public static void main(String[] args) {

        //使用泛型
        // 1. 當我們這樣寫的時候:ArrayList<Dog>  表示集合ArrayList中的元素是Dog類型
        // 2. 如果編譯器發現添加的類型不滿足要求,就會報錯
        // 3.在遍歷的時候,可以直接取出Dog類型,而不是Object
        ArrayList<Dog> arrayList = new ArrayList<Dog>();
        arrayList.add(new Dog("旺財",10));
        arrayList.add(new Dog("發財",1));
        arrayList.add(new Dog("小黃",5));

        //假設,我們的程式員不小心添加了一隻貓,就會報錯
        // arrayList.add(new Cat("招財貓",8));

        System.out.println("====使用泛型====");
        for (Dog dog:arrayList) {
            System.out.println(dog.getName()+"-"+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 void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = 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 void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
image-20220829154423564

泛型的好處:

  1. 編譯時,檢查添加元素的類型,提高了安全型

  2. 減少了類型轉換的次數,提高效率

    如上面例子所示:不使用泛型的時候,Dog對象放到ArrayList里會先轉成Object類型,在取出的時候還要再轉換成Dog類型(Dog--加入-->Object--取出-->Dog)

    使用了泛型,則放入和取出時都不需要類型轉換,提高效率(Dog-->-Dog-->Dog)

  3. 不再提示編譯警告

    不添加@SuppressWarnings("all")編譯器也不再警告

2.泛型介紹

泛型是一種可以表示數據類型的 數據類型

如下圖:public class ArrayList<E>{} E 稱為泛型

image-20220829161048526


泛(廣泛)型(類型)===>integer,String,Dog,……

  1. 泛型又稱參數化類型,是jdk5.0出現的新特性,解決數據類型的安全性問題
  2. 在類聲明或者實例化時只要指定好需要的具體類型即可
  3. Java泛型可以保證如果程式在編譯時沒有發出警告,運行就不會產生ClassCastException異常。同時,代碼更加簡潔、健壯
  4. 泛型的作用是:可以在類聲明時 通過一個標識 表示類中的某個屬性,或者是某個方法的返回值的類型,或者是參數類型

例子:

package li.generic;

public class Generic03 {
    public static void main(String[] args) {
        Person<String> person = new Person<String>("jack");
        person.showCalss();//class java.lang.String
        /*
       可以這樣理解:上面的Person類變為了
       class Person{
            String s;

             public Person(String s) {
                this.s = s;
            }

            public String f() {
             return s;
            }
        }

        */
        Person<Integer> person1 = new Person<Integer>(100);
        person1.showCalss();//class java.lang.Integer
        /*  可以這樣理解:上面的Person類變為了
       class Person{
            Integer s;

             public Person(Integer s) {
                this.s = s;
            }

            public Integer f() {
             return s;
            }
        }
        */

    }
}

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 showCalss(){
        System.out.println(s.getClass());//顯示s的運行類型
    }
}

註意:E的數據類型在定義 Person 對象的時候指定,即在編譯期間,就確定E是什麼類型

泛型是一種可以表示數據類型的 數據類型

3.泛型的語法

3.1泛型的聲明

interface 介面<T>{} class 類<K,V>{}//比如:List、ArrayList

說明:

1)其中,T,K,V不代表值,而是表示類型

2)任意字母都可以。常用T表示,是Type的縮寫

3.2泛型的實例化

要在類名後面指定類型參數的值(類型),如:

(1)List<String> strList = new ArrayList<String>() ;

(2)Iterator<Customer> iterator = customer.iterator();

3.3泛型使用舉例

例子:泛型使用舉例:

練習:

  1. 創建三個學生對象
  2. 學生對象放入到HashSet中使用
  3. 放入到HashMap中,要求Key是String name ,Value就是學生對象
  4. 使用兩種方法遍歷

練習:

package li.generic;

import java.util.*;

public class GenericExercise {
    public static void main(String[] args) {

        //使用泛型的方法給HashSet放入三個學生對象
        HashSet<Student> students = new HashSet<Student>();
        students.add(new Student("jack", 18));
        students.add(new Student("marry", 17));
        students.add(new Student("link", 123));

        //使用HashSet的增強for
        System.out.println("===使用HashSet的增強for===");
        for (Student student : students) {
            System.out.println(student);
        }


        //使用泛型的方法給HashMap放入三個學生對象
        HashMap<String, Student> hm = new HashMap<String, Student>();
        hm.put("jack", new Student("jack", 18));
        hm.put("lucy", new Student("lucy", 28));
        hm.put("olin", new Student("olin", 16));


        //迭代器 EntrySet
        System.out.println("===迭代器 EntrySet===");
        Set<Map.Entry<String,Student>> entries = hm.entrySet();
       Iterator<Map.Entry<String,Student>> iterator1 = entries.iterator();
        while (iterator1.hasNext()) {
            Map.Entry<String, Student> next =  iterator1.next();
            System.out.println(next.getKey()+"-"+next.getValue());

        }
    }
}

class Student {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
image-20220829174053923

3.4泛型使用的註意事項和細節

  1. interface List<T>{} ,public class HashSet<E>{}..等等

    說明:T,E只能是引用類型

    看看下麵語句是否正確?

    List<Integer> list = new ArrayList<Integer>();//正確

    List<int> list2 = new ArrayList<int>();//錯誤

  2. 在指定泛型具體類型後,可以傳入該類型或者其子類類型

  3. 泛型使用形式

    3.1 在實際的開發中,我們往往簡寫,編譯器會進行類型推斷,推薦使用下麵的寫法
    ArrayList<Integer> list1 = new ArrayList<>();

    3.2 泛型預設是Object類型,即如果沒有給泛型指定類型,預設就是Object:

    ArrayList arrayList = new ArrayList();//等價為 ArrayList<Object> arrayList = new ArrayList<>();

例子:

package li.generic;

import java.util.ArrayList;
import java.util.List;

public class GenericDetail {
    public static void main(String[] args) {
        //1.給泛型指向的數據類型要求是引用類型,不能是基本數據類型
        List<Integer> list = new ArrayList<Integer>();//ok
        //List<int> list2 = new ArrayList<int>();錯誤

        //2.因為 E指定了A類型,構造器傳入了 new A()
        Pig<A> aPig = new Pig<A>(new A());//將A類型賦給泛型E,說明Pig構造器可以接收的是A類型的對象

        //在指定泛型具體類型後,可以傳入該類型或者其子類類型
        Pig<A> aPig2 = new Pig<A>(new B());

        aPig.showClass();//class li.generic.A
        aPig2.showClass();//class li.generic.B

        // 3.泛型的使用形式
        //在實際的開發中,我們往往簡寫,編譯器會進行類型推斷,推薦使用下麵的寫法
        ArrayList<Integer> list1 = new ArrayList<>();
        
    }
}
class A{}
class B extends A{}
class Pig<E>{
    E e;

    public Pig(E e) {
        this.e = e;
    }

    public void showClass(){
        System.out.println(e.getClass());//運行類型
    }
}

4.泛型課堂練習

定義Employee類

  1. 該類包括:private成員變數name,sal,birthday,其中birthday為MyDate類的對象;

  2. 為每一個屬性定義getter、setter方法;

  3. 重寫toString方法輸出name,sal,birthday;

  4. MyDate類包括:private成員變數year,month,day。併為為每一個屬性定義getter、setter方法;

  5. 創建該類的3個對象,並把這些對象放入ArrayList集合中(ArrayList需使用泛型來定義),對集合中的元素進行排序,並遍歷輸出:

    排序方式:調用ArrayList的sort方法,傳入Comparator對象(使用泛型),先按照name排序,如果name相同,則按照生日日期的先後排序。(即定製排序)

練習:

package li.generic;

import java.util.ArrayList;
import java.util.Comparator;

public class GenericHomework {
    public static void main(String[] args) {
        ArrayList<Employee> employees = new ArrayList<>();
        employees.add(new Employee("tom", 20000, new MyDate(1980, 12, 11)));
        employees.add(new Employee("jack", 12000, new MyDate(2001, 12, 12)));
        employees.add(new Employee("tom", 50000, new MyDate(1980, 12, 10)));

        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                
//                //比較name
//                int i = o1.getName().compareTo(o2.getName());
//                if (i != 0) {
//                    return i;
//                }
//                //如果name相同,就比較birthday-year
//                int yearMinus = o1.getBirthday().getYear()-o2.getBirthday().getYear();
//                if (yearMinus !=0) {
//                    return yearMinus;
//                }
//                //如果year相同,就比較month
//                int monthMinus = o1.getBirthday().getMonth()-o2.getBirthday().getMonth();
//                if (monthMinus !=0) {
//                    return monthMinus;
//                }
//                //如果month相同,就比較mday
//                return o1.getBirthday().getDay()-o2.getBirthday().getDay();

                //比較name
                int i = o1.getName().compareTo(o2.getName());
                if (i != 0) {
                    return i;
                }
                
                //下麵是對birthday的比較,因此,我們最好把日期的比較放到MyDate類完成
                //封裝後的維護性和復用性更好
               return o1.getBirthday().compareTo(o2.getBirthday());
            }
        });

        for (Employee e : employees) {
            System.out.println(e);
        }
    }
}

class Employee {
    private String name;
    private int sal;
    private MyDate birthday;

    public Employee(String name, int 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 int getSal() {
        return sal;
    }

    public void setSal(int sal) {
        this.sal = sal;
    }

    public MyDate getBirthday() {
        return birthday;
    }

    public void setBirthday(MyDate birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + 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 "MyDate{" +
                "year='" + year + '\'' +
                ", month='" + month + '\'' +
                ", day='" + day + '\'' +
                '}';
    }

    @Override
    public int compareTo(MyDate o) {//把 年 月 日 的比較挪到這裡

        //如果name相同,就比較birthday-year
        int yearMinus = year-o.getYear();
        if (yearMinus !=0) {
            return yearMinus;
        }
        //如果year相同,就比較month
        int monthMinus = month-o.getMonth();
        if (monthMinus !=0) {
            return monthMinus;
        }
        //如果month相同,就比較mday
        return day-o.getDay();
    }
}

image-20220829201930124


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 小記: 本章 主要瞭解命令式、聲明式、性能與可維護性的權衡、虛擬Dom的性能、運行時和編譯時。Vue就是通過權衡這幾種方式的優缺點進行框架設計 命令式、聲明式 對比 框架對比 命令式 聲明式 特點 只關註過程 只關註結果 優點 性能最高 心智負擔小,維護性高 優缺點 心智負擔大、維護性差 性能較高 ...
  • YSLaunchar-a1.0 模型 基本介紹 本文不考慮所有具體的實現方法,之後會有更完整第二版發出 該程式計劃使用 julia 語言編寫,目前版本(1.7)並不包含類(class),取而代之,我會使用 julia 提供的兩種結構體完成。 考慮了很久,我將會把所有版本,玩家列表使用字典的形式。 主 ...
  • 以下內容為本人的著作,如需要轉載,請聲明原文鏈接 微信公眾號「englyf」https://www.cnblogs.com/englyf/p/16637890.html 如果不是機緣巧合,當年轉到C++之後,恐怕很難再有機會還寫C的代碼。面向對象在現代coding中,就像聖經一樣,在碼農的口中自帶光 ...
  • 看《C++ Primer Plus》時整理的學習筆記,部分內容完全摘抄自《C++ Primer Plus》(第6版)中文版,Stephen Prata 著,張海龍 袁國忠譯,人民郵電出版社。只做學習記錄用途。 ...
  • 泛型 筆記目錄:(https://www.cnblogs.com/wenjie2000/p/16378441.html) 泛型的理解和好處 看一個需求 請編寫程式,在ArrayList中,添加3個Dog對象 Dog對象含有name和age,並輸出name和age(要求使用getXxx()) 先使用傳 ...
  • 目錄 一.OpenGL 伽馬線 1.IOS Object-C 版本 2.Windows OpenGL ES 版本 3.Windows OpenGL 版本 二.OpenGL 伽馬線 GLSL Shader 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> ...
  • JVM執行引擎的作用就是將位元組碼指令解釋或者編譯為對應平臺上的本地機器指令。簡單來說,執行引擎充當了將高級語言翻譯為機器語言的翻譯者。 ...
  • 《看漫畫學Python:有趣、有料、好玩、好用:全彩版》PDF高清版免費下載地址 內容簡介 · · · · · · Python是一門既簡單又強大的編程語言,被廣泛應用於數據分析、大數據、網路爬蟲、自動化運維、科學計算和人工智慧等領域。Python也越來越重要,成為國家電腦等級考試科目,某些中小學 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...