最近在看java編程思想(第四版)的持有容器,書上11章223頁代碼如下
在寫這個示例的時候,我發(fā)現(xiàn)紅框內(nèi)的代碼可以通過編譯,和書上不一致?
package com.xunli.holding;
import java.util.*;
class Snow {}
class Powder extends Snow {}
class Light extends Powder {}
class Heavy extends Powder {}
class Crusty extends Snow {}
class Slush extends Snow {}
public class AppleAndOrangeWithnotGenerics {
public static void main(String[] args) {
List<Snow> snow1 = Arrays.asList(
new Crusty(), new Slush(), new Powder()
);
List<Snow> snow2 = Arrays.asList(
new Light(), new Heavy()
);
List<Snow> snow3 = new ArrayList<Snow>();
Collections.addAll(snow3, new Light(), new Heavy());
List<Snow> snow4 = Arrays.<Snow>asList(new Light(), new Heavy());
}
}
這是為什么?
從 Java7 開始,官方就著手增強 Java 對泛型類型的推導(dǎo)能力,對應(yīng)的項目有 JDK7 的 JSR 334 (Project Coin) 和 JDK8 的 JEP 101: Generalized Target-Type Inference。
我看樓上有回答說 Java8 以下版本不可以編譯你的代碼,這是不對的。使用 Java7 也可以正確編譯你的代碼,因為 JDK7 對于泛型類型的推導(dǎo)不僅僅只有 “菱形推導(dǎo)”,還添加了部分目標(biāo)類型推導(dǎo)的功能,可以參考 Oracle 的官方文檔 Type Inference,看到 Target Types 這一節(jié),我摘取部分:
The Java compiler takes advantage of target typing to infer the type parameters of a generic method invocation. The target type of an expression is the data type that the Java compiler expects depending on where the expression appears. Consider the method Collections.emptyList, which is declared as follows:
static <T> List<T> emptyList();
Consider the following assignment statement:
List<String> listOne = Collections.emptyList();
This statement is expecting an instance of List<String>; this data type is the target type. Because the method emptyList returns a value of type List<T>, the compiler infers that the type argument T must be the value String. This works in both Java SE 7 and 8.
可以看到,對于 JDK7 以及之后版本的 JDK 來說,它們至少都已經(jīng)擁有了根據(jù)返回值來確定泛型類型的能力。
再回到你的代碼,比如你寫:
List<Snow> snow1 = Arrays.asList(
new Crusty(), new Slush(), new Powder()
);
編譯器可以根據(jù)你的返回值類型(List<Snow>)來推斷出你傳入的每一個參數(shù)都是一個 Snow,從而判斷參數(shù)是否正確(即判斷每一個參數(shù)的類型是否都是 Snow 或者其子類)。對于下面的代碼效果一樣:
List<Snow> powders = Arrays.asList(
new Light(), new Heavy()
);
因為 Light 和 Heavy 都是 Snow 的間接子類。
如果你不寫上返回值,而是直接寫上代碼:
Arrays.asList(
new Light(), new Heavy()
);
然后用 IntelliJ IDEA 的自動生成返回的變量的功能(我認(rèn)為 IDE 也是調(diào)用的編譯器提供的相關(guān) API 的功能,或者至少是符合編譯器要求的功能):
你會發(fā)現(xiàn)生成的是 List<Powder>,
這種時候,沒有返回值,那么編譯器會嘗試去找到傳入的所有參數(shù)的最近的交集,即 Powder,所以編譯推導(dǎo)出此時的 T 的類型為 Powder。
綜上,Java 的編譯器,從很早以前就真的開始變得越來越聰明了呢。
北大青鳥APTECH成立于1999年。依托北京大學(xué)優(yōu)質(zhì)雄厚的教育資源和背景,秉承“教育改變生活”的發(fā)展理念,致力于培養(yǎng)中國IT技能型緊缺人才,是大數(shù)據(jù)專業(yè)的國家
達(dá)內(nèi)教育集團(tuán)成立于2002年,是一家由留學(xué)海歸創(chuàng)辦的高端職業(yè)教育培訓(xùn)機構(gòu),是中國一站式人才培養(yǎng)平臺、一站式人才輸送平臺。2014年4月3日在美國成功上市,融資1
北大課工場是北京大學(xué)校辦產(chǎn)業(yè)為響應(yīng)國家深化產(chǎn)教融合/校企合作的政策,積極推進(jìn)“中國制造2025”,實現(xiàn)中華民族偉大復(fù)興的升級產(chǎn)業(yè)鏈。利用北京大學(xué)優(yōu)質(zhì)教育資源及背
博為峰,中國職業(yè)人才培訓(xùn)領(lǐng)域的先行者
曾工作于聯(lián)想擔(dān)任系統(tǒng)開發(fā)工程師,曾在博彥科技股份有限公司擔(dān)任項目經(jīng)理從事移動互聯(lián)網(wǎng)管理及研發(fā)工作,曾創(chuàng)辦藍(lán)懿科技有限責(zé)任公司從事總經(jīng)理職務(wù)負(fù)責(zé)iOS教學(xué)及管理工作。
浪潮集團(tuán)項目經(jīng)理。精通Java與.NET 技術(shù), 熟練的跨平臺面向?qū)ο箝_發(fā)經(jīng)驗,技術(shù)功底深厚。 授課風(fēng)格 授課風(fēng)格清新自然、條理清晰、主次分明、重點難點突出、引人入勝。
精通HTML5和CSS3;Javascript及主流js庫,具有快速界面開發(fā)的能力,對瀏覽器兼容性、前端性能優(yōu)化等有深入理解。精通網(wǎng)頁制作和網(wǎng)頁游戲開發(fā)。
具有10 年的Java 企業(yè)應(yīng)用開發(fā)經(jīng)驗。曾經(jīng)歷任德國Software AG 技術(shù)顧問,美國Dachieve 系統(tǒng)架構(gòu)師,美國AngelEngineers Inc. 系統(tǒng)架構(gòu)師。