chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內(nèi)不再提示

深入了解Java泛型——從前世今生到PECS原則

OSC開源社區(qū) ? 來源:OSC開源社區(qū) ? 2024-11-21 11:45 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

本文主要介紹泛型誕生的前世今生,特性,以及著名PECS原則的由來。

在日常開發(fā)中,必不可少的會使用到泛型,這個過程中經(jīng)常會出現(xiàn)類似“為什么這樣會編譯報錯?”,“為什么這個列表無法添加元素?”的問題,也會出現(xiàn)感嘆Java的泛型限制太多了很難用的情況。

為了更好的使用泛型,就需要更深地了解它,因此本文主要介紹泛型誕生的前世今生,特性,以及著名PECS原則的由來。

泛型的誕生

背景

在沒有泛型之前,必須使用Object編寫適用于多種類型的代碼,想想就令人頭疼,并且非常的不安全。同時由于數(shù)組的存在,設計者為了讓其可以比較通用的進行處理,也讓數(shù)組允許協(xié)變,這又為程序添加了一些天然的不安全因素。為了解決這些情況,Java的設計者終于在Java5中引入泛型,然而,正是因為引入泛型的時機較晚,為了兼容先前的代碼,設計者也不得不做出一些限制,來讓使用者(也就是我們)以難受換來一些安全。

優(yōu)點

簡單來說,泛型的引入有以下好處:

程序更加易讀

安全性有所保證

以ArrayList舉例,在增加泛型類之前,其通用性是用繼承來實現(xiàn)的,ArrayList類只維護一個Object引用的數(shù)組,當我們使用這個工具類時,想要獲取指定類型的對象必須經(jīng)過強轉:

import java.util.ArrayList;
import java.util.Date;

public class Main {
  public static void main(String[] args) {
    ArrayList list = new ArrayList();
    //強制類型轉換
    String res = (String) list.get(0);
    //十分不安全的行為
    list.add(new Date());
  }
}

這種寫法在編譯類型時不會報錯,但一旦使用get獲取結果并試圖將Date轉換為其他類型時,很有可能出現(xiàn)類型轉換異常,為了解決這種情況,類型參數(shù)應用而生。

類型參數(shù)

類型參數(shù)(Type parameter)使得ArrayList以及其他可能用到的集合類能夠方便的指示虛擬機其包含元素的類型:?

import java.util.ArrayList;


public class Main {
  public static void main(String[] args) {
    ArrayList objects = new ArrayList<>();
    objects.add("Hello");
  }
}

這使得代碼具有更好的可讀性,并且在調(diào)用get()的時候,無需進行強轉,最重要的是,編譯器終于可以檢查一個插入操作是否符合要求,運行時可能出現(xiàn)的各種類型轉換錯誤得以在編譯階段就被阻止。

import java.util.ArrayList;
import java.util.Date;


public class Main {
  public static void main(String[] args) {
    ArrayList objects = new ArrayList<>();
    //we can do it like that
    objects.add("Hello");
    //wrong example
    objects.add(new Date());
  }
}

基本用法

一般來說,使用泛型工具類很容易,但是自己編寫會相對困難很多,設計者必須考慮的相當周全才能使自己的泛型類庫比較完善。

泛型類

泛型類是有一個或者多個類型變量的類,泛型類中的屬性可以全都不是泛型,不過一般不會這樣做,畢竟類型變量在整個類上定義就是用于指定方法的返回類型以及字段的類型,定義代碼如下:?

public class Animal {
  private String name;
  private T mouth;
  
  public T getMouth(){
    return mouth;
  }
}

泛型類可以有多個類型變量:

public class Animal {
  private String name;
  private T mouth;
  private U eyes;


  public T getMouth(){
    return mouth;
  }
}

泛型方法

泛型方法可以在普通類中定義,也可以在泛型類中定義,例如:

public class Animal {
  private T value;
  public static  T get(T... a){
    return a[a.length-1];
  }
  public T getFirst(){
    return value;
  }
}

類型擦除

虛擬機沒有泛型類型對象,也就是說,所有對象在虛擬機中都屬于普通類,這意味著在程序編譯并運行后我們的類型變量會被擦除(erased)并替換為限定類型,擦掉類型參數(shù)后的類型就叫做原始類型(raw type),正是因為有類型參數(shù),所以下面的比較結果會為true:

256ea9d8-9f6d-11ef-93f3-92fbcf53809c.jpg

?

這里的替換規(guī)則我個人理解為:“替換最近上界”,也就是無限定符修飾,則為頂級父類Object,如果有,則會替換為其指定的類型。最直觀的示例如下,這就是類型擦除的體現(xiàn):

257bed8c-9f6d-11ef-93f3-92fbcf53809c.jpg

?

259165e0-9f6d-11ef-93f3-92fbcf53809c.jpg

??

前面說過,泛型是在1.5才提出的,因此類型擦除的目的就是為了保證已有的代碼和類文件依然合法,也就是向低版本兼容。這樣做會帶來幾個問題:

1.類型參數(shù)不支持基本類型,只支持引用類型,這是因為泛型會被擦除為具體類型,而Object不能存儲基本類型的值。

運行時你只能對原始類型進行類型檢測:

2598cc86-9f6d-11ef-93f3-92fbcf53809c.jpg

?

2.不能實例化類型參數(shù)

不能實例化泛型數(shù)組,因為類型擦除會將數(shù)組變?yōu)镺bject數(shù)組,如果允許實例化,極易造成類型轉換異常。

強制轉換

在編寫泛型方法調(diào)用時,如果擦出了返回類型,編譯器會插入強制類型轉換。例如下面的代碼:

public class Main {
  public static void main(String[] args) {
    Animal pair = new Animal<>();
    Integer first = pair.getFirst();
  }
}

getFirst擦除類型后的返回類型是Object,編譯器自動插入轉換到Integer的強制類型轉換,也就是說,編譯器把這個方法調(diào)用轉換為兩條虛擬機指令:

對原始方法的調(diào)用。

將返回的Object類型強制轉換為Integer類型。

方法橋接

子類重寫父類方法時,必須和父類保持相同的方法名稱,參數(shù)列表和返回類型。那么問題來了,如果按照之前的思路來講,當泛型父類或接口的類型參數(shù)被擦除了,那么子類豈不是不構成重寫條件?(參數(shù)類型很可能變化):

擦除前:

25aec6c6-9f6d-11ef-93f3-92fbcf53809c.jpg

?

擦除后:

25b99844-9f6d-11ef-93f3-92fbcf53809c.jpg

?

為了解決這個事情,Java引入了橋接方法,為每個繼承/實現(xiàn)泛型類/接口的子類服務,以此保持多態(tài)性,字節(jié)碼如下:

25c50206-9f6d-11ef-93f3-92fbcf53809c.jpg

?

(圖片來源:RudeCrab)

其實現(xiàn)原理,就是重寫擦除后的父類方法,并在其內(nèi)部委托了原始的子類方法,巧妙繞過了擦除帶來的影響。不僅如此,就算不是泛型類,當子類方法重寫父類方法的返回類型是父類返回類型的子類時,編譯器也會生成橋接方法來滿足重寫的規(guī)則。

總結

Java核心技術中總結的非常到位:

虛擬機中沒有泛型,只有普通的類和方法。

所有的類型參數(shù)都會替換為他們的限定類型。

會合成橋接方法來保持多態(tài)。

為保持類型安全性,必要時會插入強制類型轉換。

變型(Variant)與數(shù)組

變型是類型系統(tǒng)中很重要的概念,主要有三個規(guī)則協(xié)變,逆變,和不變:

25cecc46-9f6d-11ef-93f3-92fbcf53809c.jpg

?

這三個類型可以解釋為:假設有一個類型構造器f,它可以將已知類型轉換為另一種類型,那么,有Animal父類和Dog子類。

則f(Dog)是f(Animal)的子類,稱為協(xié)變;

則f(Dog)是f(Animal)的父類,成為逆變;

則f(Dog)和f(Animal)沒有任何關系;

而這個f(),可以是泛型,可以是數(shù)組,也可以是方法。

知道了以上概念,我們需要直接指出,泛型默認是不支持協(xié)變的,原因很簡單,類型安全:如果允許協(xié)變,可能會造成類型轉換異常。而數(shù)組支持協(xié)變,正如文章開頭所說,就是設計者希望可以對數(shù)組進行比較通用的處理,防止方法為每一種類型編寫重復邏輯,這樣做也確實導致為數(shù)組賦值元素時可能會拋出運行時異常ArrayStoreException,這是一個很危險的坑。Effective Java中直接指出允許數(shù)組協(xié)變是Java的缺陷,我想這也是要多用列表而不用數(shù)組的原因之一。

泛型協(xié)變—PECS原則

為了讓泛型也支持多態(tài),讓其支持協(xié)變是很必要的,最常用的場景:我們想讓一個方法接受一個集合,并做統(tǒng)一的邏輯處理,如果泛型不支持協(xié)變,這種很基本的需求都會成為奢望。

上界

讓泛型支持協(xié)變很簡單,只需要使用? extends的組合即可實現(xiàn),?稱為通配符,這種組合方式聲明了類型的上界,標識泛型可接受的類型只能是指定類型或是其子類。在這里,ElectricVehicle和Diesel均是繼承自Car。

25d26144-9f6d-11ef-93f3-92fbcf53809c.jpg

?

為了杜絕可協(xié)變后出現(xiàn)類似于數(shù)組一樣的安全隱患,泛型設計采用了“一刀切”的方式,即:只要聲明了上界,除了null之外,一律不準傳入給泛型。說白了,就是只讀不寫,這樣當然可以保證安全性。

25f06be4-9f6d-11ef-93f3-92fbcf53809c.jpg

?

到這里可以順便說一下集合的設計,可以注意到集合中只有add方法是泛型參數(shù),而其余方法并不是,為何要這樣設計,為何不把其余方法的參數(shù)類型也改為E?其原因就是在于,如果將contains和remove改為E,那么聲明上界之后,調(diào)用這兩個方法會引發(fā)編譯錯誤,然而這兩個方法均為類型安全方法,自然不可聲明為E,add作為很明顯的寫方法,自然也需要用E作為參數(shù)類型,到這里,不得不感嘆類庫設計者的想法獨到。

25fa262a-9f6d-11ef-93f3-92fbcf53809c.jpg

?

下界

對應協(xié)變的上界,自然有逆變的下界,很自然的,我們使用? super的組合來聲明一個泛型的下界,來表示可以接收本類型或者其父類型。

2608e958-9f6d-11ef-93f3-92fbcf53809c.jpg

?

而且相對應的,正是由于最多只能接收父類型泛型,所以不會有類型轉換失敗的風險,因此逆變可以添加元素,不過添加的元素類型只能是指定類型和其子類,切記不要把添加元素和接收泛型類參數(shù)給弄混了。

有利有弊,雖然逆變沒有了協(xié)變只讀不寫的限制,但是讀取元素時將不能確定具體的類型,只能用Object來接收:

261b1fba-9f6d-11ef-93f3-92fbcf53809c.jpg

?

PECS

正如上面對上下界的描述,我們已經(jīng)明白了大致的應用場景,當我們需要只讀不寫時,就用協(xié)變,只寫不讀,就用逆變。又想讀又想寫,我們應該指明準確的泛型類型。

注明的PECS原則就總結了這一點,PECS(Prodcuer extends Consumer super),也就是說,作為元素的生產(chǎn)者Prodcuer,要用協(xié)變,支持元素的讀取,而作為消費者Consumer,要支持逆變,支持元素的寫入。

2621182a-9f6d-11ef-93f3-92fbcf53809c.jpg

?

Collections的copy方法就非常好的印證了這一點:

262c6c66-9f6d-11ef-93f3-92fbcf53809c.jpg

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學習之用,如有內(nèi)容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • JAVA
    +關注

    關注

    20

    文章

    2997

    瀏覽量

    115609
  • 程序
    +關注

    關注

    117

    文章

    3836

    瀏覽量

    84737
  • specs
    +關注

    關注

    0

    文章

    5

    瀏覽量

    1718

原文標題:深入了解Java泛型——從前世今生到PECS原則

文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    芯片裝甲的前世今生

    一前言眾所周知,晶圓的特性如同玻璃一樣容易破碎,但為什么做成成品的IC又能通過高震動與跌落可靠性測試,并且能在高溫環(huán)境下非常穩(wěn)定運行?這其實是一個關鍵的半導體技術——封裝的功勞。它像一道“防護城墻”,既要屏蔽灰塵、水汽、沖擊,也要兼顧散熱、電性能和成本。在如今人人都知道先進半導體工藝已經(jīng)先進到2nm的今天,對于不起眼的封裝技術,卻鮮有人熟知。接下來,讓我們從
    的頭像 發(fā)表于 11-25 11:34 ?87次閱讀
    芯片裝甲的<b class='flag-5'>前世</b><b class='flag-5'>今生</b>

    深入了解X-ray自動設備的核心優(yōu)勢與應用領域

    。面對復雜多變的工業(yè)環(huán)境和嚴格的品質(zhì)標準,企業(yè)如何借助自動化X射線檢測設備優(yōu)化生產(chǎn)流程、提升檢測準確度?本文將圍繞X-ray自動設備的核心優(yōu)勢與應用領域展開詳盡解讀,幫助您深入了解該技術帶來的變革與價值。無論您是工廠質(zhì)量管
    的頭像 發(fā)表于 11-04 14:34 ?121次閱讀

    深入了解API:詳解應用程序接口的作用和原理

    都是不可或缺的組成部分。本文將深入探討API的作用和原理,幫助讀者更好地理解和應用API。 淘寶/天貓獲得淘寶商品詳情 API 返回值說明 公共參數(shù) ??前往測試?? 名稱 類型 必須 描述 key
    的頭像 發(fā)表于 11-03 09:37 ?147次閱讀

    深入了解X-ray無損探傷技術的核心優(yōu)勢與應用-智誠精展

    和安全性的要求日益提高,X-ray無損檢測憑借其成像清晰、穿透力強、檢測精度高等特點,成為無損檢測領域的重要手段。本文將深入剖析X-ray無損探傷技術的核心優(yōu)勢及其實際應用場景,幫助相關企業(yè)和技術人員了解如何通過高效、精準的X
    的頭像 發(fā)表于 10-24 11:18 ?199次閱讀

    深入了解水質(zhì)探頭的工作原理與應用

    隨著環(huán)保意識的不斷增強和水資源管理需求的提升,水質(zhì)監(jiān)測成為各行業(yè)關注的焦點。特別是在工業(yè)生產(chǎn)、污水處理和飲用水安全領域,精準、實時的水質(zhì)探測技術得到了快速發(fā)展。水質(zhì)探頭作為關鍵監(jiān)測設備,因其高效、智能的檢測能力,越來越受到行業(yè)青睞。根據(jù)最新市場報告,智能水質(zhì)探頭市場預計在未來五年內(nèi)以年均超過12%的增長速度穩(wěn)步擴大。您是否也在尋找一種能準確反映水體環(huán)境變化且便于維護的水質(zhì)監(jiān)測方案?本文將通過詳細解讀水質(zhì)探
    的頭像 發(fā)表于 10-23 14:00 ?172次閱讀

    深入了解X-ray無損探傷技術的優(yōu)勢與應用領域

    的優(yōu)勢和實際應用領域了解不夠。本文將深入探討X-ray無損探傷技術的獨特優(yōu)勢及其廣泛的應用場景,幫助企業(yè)做出更明智的決策,提升自我品牌的信任度。 什么是X-ray無損探傷技術? X-ray無損探傷技術,顧名思義,是利用X射線對材料內(nèi)部進行檢查的
    的頭像 發(fā)表于 09-16 14:59 ?537次閱讀

    深入了解連接器的分類與應用

    一、連接器的基本概念 連接器,就是一種電氣或者光學的零組件,能讓兩條或者好幾條電路、光路連一塊。它一般是由插頭和插座組成的,能讓設備之間很快地連上、斷開,再連上。這連接器怎么設計、有什么功能,主要得看使的地方、要傳的信號是什么樣的,還有一些物理特性,像阻抗啊、頻率啊、耐用不耐用等。 二、連接器 的 分類 連接器能按照不一樣的標準分成好多種,咱下面就說說幾個主要的分法: 1. 按結構形式分 插頭連接器:這就是設計成
    的頭像 發(fā)表于 08-25 08:50 ?431次閱讀

    如何為不同的電機選擇合適的驅(qū)動芯片?納芯微帶你深入了解!

    在現(xiàn)代生活中,電機廣泛使用在家電產(chǎn)品、汽車電子、工業(yè)控制等眾多應用領域,每一個電機的運轉都離不開合適的驅(qū)動芯片。納芯微提供豐富的電機驅(qū)動產(chǎn)品選擇,本期技術分享將重點介紹常見電機種類與感性負載應用,幫助大家更深入了解如何選擇合適的電機驅(qū)動芯片。
    的頭像 發(fā)表于 07-17 14:00 ?1611次閱讀
    如何為不同的電機選擇合適的驅(qū)動芯片?納芯微帶你<b class='flag-5'>深入了解</b>!

    Java Go:面向?qū)ο蟮木奕伺c云原生的輕騎兵

    Go 語言在 2009 年被 Google 推出,在創(chuàng)建之初便明確提出了“少即是多(Less is more)”的設計原則,強調(diào)“以工程效率為核心,用極簡規(guī)則解決復雜問題”。它與 Java 語言生態(tài)
    的頭像 發(fā)表于 04-25 11:13 ?498次閱讀

    深入了解U8g2與LVGL圖形庫

    在單片機開發(fā)領域,圖形顯示功能變得越來越重要。無論是工業(yè)控制界面、智能家居設備,還是手持儀器儀表,都需要一個高效且易用的圖形庫來實現(xiàn)豐富的可視化效果。U8g2 和 LVGL 就是其中兩款備受關注的圖形庫,它們各有特點,適用于不同的應用場景。今天,我們就來深入了解這兩個圖形庫。
    的頭像 發(fā)表于 02-13 11:01 ?3424次閱讀

    深入了解 PCB 制造技術:銑削

    了 PCB 銑削的復雜性、銑削工藝、其優(yōu)勢、挑戰(zhàn)和應用。 了解 PCB 銑削 PCB 銑削涉及從覆銅板上機械去除材料,以創(chuàng)建電氣隔離并形成電路圖案。與使用化學溶液溶解不需要的銅的傳統(tǒng)蝕刻方法不同,銑削使用精確控制的銑削鉆頭來物理雕刻出所需的痕跡。該過程通
    的頭像 發(fā)表于 01-26 21:25 ?1098次閱讀
    <b class='flag-5'>深入了解</b> PCB 制造技術:銑削

    深入了解渦街流量計 原理及內(nèi)部構造

    渦街流量計是一種常用的流量測量儀表,LUB系列渦街流量計的內(nèi)部構造與原理密切相關,共同構成了其高精度、寬量程比和穩(wěn)定運行的基礎。本文將深入介紹渦街流量計的原理及內(nèi)部構造,以便更好地了解渦街流量計
    的頭像 發(fā)表于 01-06 15:17 ?1663次閱讀

    安泰功率放大器應用:納米材料的前世今生

    ,因此在各個領域具有廣泛的應用前景。那么你知道納米材料是如何被發(fā)現(xiàn),又是如何走入我們的生活,獲得長足發(fā)展的嗎?今天Aigtek安泰電子帶大家詳細了解一下。 納米材料的前世今生 1861年,隨著膠體化學的建立,科學家們開始了對直徑
    的頭像 發(fā)表于 01-02 14:05 ?680次閱讀
    安泰功率放大器應用:納米材料的<b class='flag-5'>前世</b><b class='flag-5'>今生</b>

    如何為不同的電機選擇合適的驅(qū)動芯片?納芯微帶你深入了解

    在現(xiàn)代生活中,電機廣泛使用在家電產(chǎn)品、汽車電子、工業(yè)控制等眾多應用領域,每一個電機的運轉都離不開合適的驅(qū)動芯片。納芯微提供豐富的電機驅(qū)動產(chǎn)品選擇,本期技術分享將重點介紹常見電機種類與感性負載應用,幫助大家更深入了解如何選擇合適的電機驅(qū)動芯片。
    的頭像 發(fā)表于 12-23 09:58 ?1725次閱讀
    如何為不同的電機選擇合適的驅(qū)動芯片?納芯微帶你<b class='flag-5'>深入了解</b>!

    光耦合器的前世今生:從誕生現(xiàn)代應用的演變

    光耦合器是一種重要的電子元件,其在電子信號隔離和傳輸中的作用不可替代。自20世紀60年代首次被研發(fā)以來,光耦合器經(jīng)歷了從基礎隔離器件高性能元件的不斷演化,在現(xiàn)代電子設備中占據(jù)了重要地位。本文將深入探討光耦合器的發(fā)展歷程、技術特點以及在當今科技領域中的廣泛應用。
    的頭像 發(fā)表于 12-13 16:16 ?831次閱讀
    光耦合器的<b class='flag-5'>前世</b><b class='flag-5'>今生</b>:從誕生<b class='flag-5'>到</b>現(xiàn)代應用的演變