亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

Unchecked Conversion 導(dǎo)致的 Java 方法返回類型變更

liangzai_cool / 781人閱讀

摘要:?jiǎn)栴}在遇到有同學(xué)反饋了個(gè)問題第一眼的感覺應(yīng)該是泛型擦除和類型推斷導(dǎo)致的但當(dāng)我嘗試去徹底解釋這個(gè)問題的時(shí)候才發(fā)現(xiàn)關(guān)鍵原因是如果在調(diào)用方法時(shí)有那么方法返回的是定義中返回類型經(jīng)過擦除后的結(jié)果具體問題是這個(gè)樣子的錯(cuò)誤不兼容的類型無法轉(zhuǎn)換為猜測(cè)

問題

在 v2 遇到有同學(xué)反饋了個(gè)問題, 第一眼的感覺應(yīng)該是泛型擦除(Type Erasure)和類型推斷(Type Inference)導(dǎo)致的. 但當(dāng)我嘗試去徹底解釋這個(gè)問題的時(shí)候, 才發(fā)現(xiàn)關(guān)鍵原因是: 如果在調(diào)用方法時(shí)有 unchecked conversion, 那么方法返回的是定義中返回類型經(jīng)過擦除(erasure)后的結(jié)果.

具體問題是這個(gè)樣子的:

public static List methodA(Collection stringCollection) {
    List stringList = new ArrayList<>();
    for (String s : stringCollection) {
        stringList.add(s);
    }
    return stringList;
}

public static void methodB(String s) {}

public static void main(String args[]) {
    // ok
    methodA((Collection) new ArrayList()).stream().forEach(p -> methodB(p));

    // compile error
    // Question.java:29: 錯(cuò)誤: 不兼容的類型: Object無法轉(zhuǎn)換為String
    // methodA((Collection) map.get("A")).stream().forEach(p -> methodB(p));
    //                                                                  ^
    methodA((Collection) new ArrayList()).stream().forEach(p -> methodB(p));
}
猜測(cè)過程

如果對(duì) type erasure, unchecked warning 不太熟悉, 可以先閱讀后幾節(jié).

依我的理解, lambda 中 p 的類型應(yīng)該被推斷為 String. 考慮 streamforEach 的定義為 Stream Collection.stream(), void Stream.forEach(Consumer action). 整個(gè)類型推斷的過程應(yīng)該如下:

List stringList = methodA(...);
Stream stringStream = stringList.stream();
stringStream.forEach(p -> methodB(p));

但從實(shí)際編譯的結(jié)果來看, methodA((Collection) new ArrayList()) 版本是符合預(yù)期的, 而 methodA((Collection) new ArrayList()) 版本中, p 的類型被推斷為 Object.

有了兩個(gè)版本的對(duì)比, 很容易就會(huì)去猜測(cè)是不是 mehtodA 返回的結(jié)果因?yàn)槿雲(yún)㈩愋偷牟煌煌? 但tm我就走歪了, 因?yàn)橛诚裰袥]有什么情況下方法返回類型會(huì)和定義不一致, 所以我先去排查了一遍泛型擦除, 類型推斷, Java 對(duì) Lambda 的處理方式等. 直到最后走頭無路,才嘗試去看返回類型是否有貓膩.

最終發(fā)現(xiàn)報(bào)錯(cuò)版本返回的結(jié)果類型為 raw type List, 而不是預(yù)期的 parameterzied type List. 驗(yàn)證的代碼如下:

Collection rawCollection = new ArrayList();
// methodA 返回的是 raw type List, 此處賦值會(huì)因?yàn)?parameterzied type 指向 raw type 而導(dǎo)致 unchecked warning
List stringList = methodA(rawCollection);

官方的解釋 是:

Otherwise, if unchecked conversion was necessary for the method to be applicable, then the result type is the erasure (§4.6) of the method"s declared return type.

嗯, 報(bào)錯(cuò)版本的傳入?yún)?shù)類型是 Collection, 而 methodA 定義的參數(shù)類型為 Collection, 調(diào)用觸發(fā) unchecked conversion.

泛型擦除

Generic type 是泛型的定義, 由 Java 傳統(tǒng)的類型結(jié)合 type parameter 組成.
通過提供具體的 type argument, generic type 實(shí)例化成為 parameterized type.

引用 Java Generic FAQs 中的內(nèi)容, 泛型擦除指的是: 在編譯過程中通過消除 type parameter 和 type argument 來將同一 generic type 對(duì)應(yīng)的不同實(shí)例映射成同一個(gè)類的過程.
具體可以分為兩個(gè)部分:

Parameterized type 的 type parameters 被刪除.

Generic type 中的 type arguments 被替換為具體的類型.

在泛型擦除的過程中, 編譯器可能按需加入額外的方法和類型轉(zhuǎn)換來保證編譯結(jié)果的正確性.

unchecked warning

uncheked warning 在編譯期間產(chǎn)生, 表示編譯器無法保證完全的類型安全, 當(dāng)然也不代表一定類型不安全.
產(chǎn)生的幾種場(chǎng)景基本都和泛型有關(guān). 和本文關(guān)聯(lián)的場(chǎng)景是: 將 parameterized type 指向 raw type, 比如 List stringList = new ArrayList()

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/73069.html

相關(guān)文章

  • Java? 教程(泛型原始類型

    泛型原始類型 原始類型是沒有任何類型參數(shù)的泛型類或接口的名稱,例如,給定Box泛型類: public class Box { public void set(T t) { /* ... */ } // ... } 要?jiǎng)?chuàng)建參數(shù)化類型的Box,請(qǐng)為形式類型參數(shù)T提供實(shí)際類型參數(shù): Box intBox = new Box(); 如果省略實(shí)際的類型參數(shù),則創(chuàng)建一個(gè)原始類型Box: Box...

    史占廣 評(píng)論0 收藏0
  • java異常設(shè)計(jì)和使用

    摘要:異常處理作用調(diào)試程序定位缺陷。對(duì)異常的處理是系統(tǒng)容錯(cuò)可靠性的一環(huán)。拋出需要具體子異常捕獲同時(shí)也需要具體子異常不同子異常處理會(huì)不同。如有基礎(chǔ)基類異常調(diào)用者可以選擇使用這個(gè)基類該類下面的所有子異常使用統(tǒng)一處理也可以單獨(dú)對(duì)子異常處理。 showImg(https://segmentfault.com/img/bVbrm5g); 1 背景 1年前的文章,源于Sonar靜態(tài)代碼掃描中,項(xiàng)目歷史代...

    sshe 評(píng)論0 收藏0
  • Java知識(shí)點(diǎn)總結(jié)(注解-內(nèi)置注解)

    摘要:知識(shí)點(diǎn)總結(jié)注解內(nèi)置注解知識(shí)點(diǎn)總結(jié)注解定義在中,此注釋只適用于修飾方法,表示一個(gè)方法聲明打算重寫父類的另一個(gè)方法聲明。此注釋可用于修飾方法屬性類,表示不鼓勵(lì)程序員使用這樣的元素,通常是因?yàn)樗芪kU(xiǎn)或存在更好的選擇。 Java知識(shí)點(diǎn)總結(jié)(注解-內(nèi)置注解) @(Java知識(shí)點(diǎn)總結(jié))[Java, 注解] @Override 定義在java.lang.Override 中,此注釋只適用于修飾方法...

    J4ck_Chan 評(píng)論0 收藏0
  • Java? 教程(類型推斷)

    類型推斷 類型推斷是Java編譯器查看每個(gè)方法調(diào)用和相應(yīng)聲明的能力,以確定使調(diào)用適用的類型參數(shù),推理算法確定參數(shù)的類型,如果可用,還確定分配或返回結(jié)果的類型,最后,推理算法嘗試查找適用于所有參數(shù)的最具體類型。 為了說明最后一點(diǎn),在下面的示例中,推斷確定傳遞給pick方法的第二個(gè)參數(shù)是Serializable類型: static T pick(T a1, T a2) { return a2; } ...

    JerryC 評(píng)論0 收藏0
  • Java異常處理最佳實(shí)踐

    摘要:然而,我更傾向于使用來單元測(cè)試來文檔化異常。單元測(cè)試允許我在使用中查看異常,并且作為一個(gè)可以被執(zhí)行的文檔來使用。通過為異常編寫單元測(cè)試,你不僅可以記錄異常如何觸發(fā),還可以使你的代碼在經(jīng)過這些測(cè)試后更加健壯。 本文是關(guān)于 Exception 處理的一篇不錯(cuò)的文章,從 Java Exception 的概念介紹起,依次講解了 Exception 的類型(Checked/Unchecked),...

    mayaohua 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<