国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Core Java筆記 7.泛型(I)

2019-11-15 00:02:50
字體:
來源:轉載
供稿:網友
Core java筆記 7.泛型(I) - 概念,語法與原理本章重點:
  • 為何要使用泛型
  • 定義泛型類
  • 定義泛型方法
  • 原理:Java 泛型代碼機制
  • 泛型與多態的沖突與解決

本文主要介紹 Java 泛型的概念和定義,以及 Java 泛型機制的實現原理。

為何要使用泛型

使用泛型程序設計,可以避免隨處可見的 Object 以及強制轉換,提高了代碼的安全性和可讀性。


定義泛型類

類型參數(type parameters): Java 和C++一樣,通過引入類型參數進行泛型編程。

泛型類(generic class): 指含有一個或者多個類型參數的類。

e.g.

package corejava.generic;/** * Created by guolong.fan on 15/5/4. */ class Pair<T> {    public Pair() { first = null; second = null;}    public Pair(T first, T second) {        this.first = first;        this.second = second;    }    public T getFirst() { return first; }    public T getSecond() { return second; }    public void setFirst(T newValue) { first = newValue; }    public void setSecond(T newValue) { second = newValue; }    PRivate T first;    private T second;}public class PairTest {    public static void main(String[] args) {        String[] Words = { "Mary", "had", "a", "little", "lamb" };                Pair<String> mm = minmax(words);        System.out.println("min = " + mm.getFirst());        System.out.println("max = " + mm.getSecond());    }    // 后面會引入 泛型方法 寫更加通用的方法    public static Pair<String> minmax(String[] a) {        if (a == null || a.length == 0) return null;        String min = a[0];        String max = a[0];        for (String ele : a) {            if (min.compareTo(ele) > 0) min = ele;            if (max.compareTo(ele) < 0) max = ele;        }        return new Pair<String>(min, max);    }}

定義泛型方法

可以在普通類中定義泛型方法。

概念: 類型推斷, 類型限定,多類型限定。

e.g.

package corejava.generic;/** * Created by guolong.fan on 15/5/4. */class ArrayAlg {    // 概念1: 最簡單的泛型方法(無類型限定)    public static <T> T getMiddle(T[] a) {        return a[a.length/2];    }    // 概念2. 類型限定:<T extends Comparable>    public static <T extends Comparable> T min(T[] a) {        if (a == null || a.length == 0) return null;        T min = a[0];        for (T ele : a) {            if (min.compareTo(ele) > 0) min = ele;        }        return min;    }    // 概念3. 多類型限定: <T extends Comparable & Serializable>        // 概念4. Comparable 本身是泛型,下一講會介紹完整的限定寫法.}public class ArrayAlgTest {    public static void main(String[] args) {        String[] names = { "John", "Q.", "Public" };        // 概念4. 類型推斷        String middle = ArrayAlg.<String>getMiddle(names);        // 簡化寫法. 編譯器會做類型推斷.        // String middle = ArrayAlg.getMiddle(names);                    // 概念5. 基本類型無法用于泛型(見后面詳解)        // int midVal = ArrayAlg.getMiddle(new double[] {120.2, 14, 34}); // Compile ERROR!!!    }}

原理:Java 泛型代碼機制

泛型類可以看成普通類的工廠! JVM 沒有泛型類型對象 —— 所有對象都是普通類對象。泛型是編譯器行為. 這是 Java 和C++泛型的本質區別,也是 Java 泛型表達能力弱的根源.

編譯器如何編譯 Java 泛型代碼

過程:

  1. 擦除(Erase): 泛型類和泛型方法無論何時定義泛型類型,都會自動提供一個對應的原始類型(raw type). 例如: Pair 的原始類型就是 Pair。
  2. 使用端(具體的泛型類):泛型代碼塊翻譯
1. erase

泛型類和泛型方法的擦除策略: 分為兩種情況:有限定和無限定(即默認 Object 限定). 無限定采用 Object 進行擦除(這是 Java 泛型不支持基本類型的原因),限定采用第一個限定(即extends 后面的第一個接口/類)擦除.

Pair 會被擦除為:

class Pair {    public Pair() { first = null; second = null;}    public Pair(Object first, Object second) {        this.first = first;        this.second = second;    }    public Object getFirst() { return first; }    public Object getSecond() { return second; }    public void setFirst(Object newValue) { first = newValue; }    public void setSecond(Object newValue) { second = newValue; }    private Object first;    private Object second;}

限定切換與性能

對于諸如:多限定的泛型類/泛型方法,會產生切換限定的概念, 采用第一個類型進行擦除,代碼必要時會插入強類型轉換來切換限定,所以為了提高效率(減少強制轉換),應該將 tagging 接口放在末尾,主要看哪個使用的多。

2. 泛型代碼塊翻譯

使用端使用具體的泛型類,這時候編譯器實際上是通過添加強制轉換代碼來完成的。

e.g.

Pair<Employee> buddies = ...;Employee buddy = buddies.getFirst();// 會被翻譯成兩條指定:Object obj = buddies.getFirst();Employee buddy = (Employee) obj;

泛型與多態的沖突與解決問題1: 類型擦除與多態沖突

假如:

public class DateInterval extends Pair<Date> {        @Override    public void setSecond(Date second) {        if (second.compareTo(getFirst()) >= 0) {            super.setSecond(second);        }    }    }

DateInterval 會被 erase 為:

public class DateInterval extends Pair {        @Override    public void setSecond(Date second) {        ... ...    }    ... ... }

這時候 DateInterval 就會有兩個 setSecond 方法,一個是從 Pair 繼承而來的方法,一個是 @Override 的 setSecond 方法。

那么問題來了,多態不是失效啦么??@Override應該會導致編譯出錯啊(@Override會執行編譯檢查)?那么 Java 編譯器是如何解決的呢??

分析:

?  javap -private DateIntervalCompiled from "DateInterval.java"public class corejava.generic.DateInterval extends corejava.generic.Pair{    public corejava.generic.DateInterval();    public void setSecond(java.util.Date);    public void setSecond(java.lang.Object); // 注: bridge method.}

其實 Java 編譯器會為 DateInterval 類生成一個 bridge method.這個 bridge method 大致實現是:

public void setSecond(java.lang.Object) {     setSecond((Date) second);}

這樣就保證了 Java 多態語義,其實 @Override 的是 setSecond(Object).

問題2: 返回值沖突與解決

如果返回值出現沖突e.g.

public class DateInterval extends Pair<Date> {    ...     @Override    public Date getSecond() {        return (Date)super.getSecond().clone();    }}

分析:

?  generic  javap -private DateInterval Compiled from "DateInterval.java"     public class corejava.generic.DateInterval extends corejava.generic.Pair{    public corejava.generic.DateInterval();    public java.util.Date getSecond();    public java.lang.Object getSecond();  // 注: bridge method}

一個驚人的發現: 竟然有兩個方法名和參數完全一樣的方法,你沒看錯,真的有兩個,你需要知道的是:JVM 能夠正確處理調用哪個方法(其實就是調用 bridge method, bridge method 再調用協變方法).

Java SE5.0 中增加了一個額外的特性: 協變。也是通過 bridge method 實現的。

小總結
  1. JVM 中沒有泛型,只有普通類和普通方法.
  2. 所有的類型參數都用它們的限定類型替換(erase).
  3. bridge method 用來解決泛型和多態的沖突.
  4. 為保持類型安全性,編譯器必要時插入強制類型轉換.

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 长春市| 宕昌县| 友谊县| 西畴县| 广德县| 图木舒克市| 卢氏县| 子洲县| 聊城市| 淮南市| 淮北市| 怀安县| 玉屏| 四会市| 芜湖县| 西贡区| 德安县| 博野县| 祁连县| 桦川县| 永善县| 隆子县| 吴川市| 富锦市| 彩票| 连江县| 吉林市| 乌审旗| 乾安县| 阿荣旗| 巧家县| 神池县| 金塔县| 南靖县| 印江| 河北区| 康平县| 赣榆县| 砚山县| 隆昌县| 扎囊县|