程序員最重要的是思想,知其然知其所以然。
小編想問,你從一開始就在使用Java嗎?你是否還記得Java被稱作為”Oak”的時期?那時,面向對象仍然是一個熱門的話題,使用C++的人們都認為Java沒有任何機會,Applets 也只是一件事情。
重載僅返回類型不同的方法
這樣的代碼無法編譯,對不?
class Test {
Object x() { return "abc"; }
String x() { return "123"; }
}
對。 Java 語言不允許兩個方法在同一個類中“等效重載”,而忽略其諸如throws自居或返回類型等的潛在的差異。
查看 Class.getMethod(String, Class…) 的 Javadoc。 其中說明如下:
請注意,類中可能有多個匹配方法,因為 Java 語言禁止在一個類聲明具有相同簽名但返回類型不同的多個方法,但 Java 虛擬機并不是如此。虛擬機中增加的靈活性可以用于實現各種語言特征。例如,可以用橋接方法實現協變參返回; 橋接方法和被重寫的方法將具有相同的簽名但擁有不同的返回類型。
小編推薦一個學JAVA的學習裙【 一三三,九三零,六九三】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多干貨和技術資料分享
哇哦,有道理。實際上下面的代碼暗藏著很多事情:
abstract class Parent {
abstract T x();
}
class Child extends Parent {
@Override
String x() { return "abc"; }
}
來看看為 Child 生成的字節碼:
// Method descriptor #15 ()Ljava/lang/String;
// Stack: 1, Locals: 1
java.lang.String x();
0 ldc [16]
2 areturn
Line numbers:
[pc: 0, line: 7]
Local variable table:
[pc: 0, pc: 3] local: this index: 0 type: Child
// Method descriptor #18 ()Ljava/lang/Object;
// Stack: 1, Locals: 1
bridge synthetic java.lang.Object x();
0 aload_0 [this]
1 invokevirtual Child.x() : java.lang.String [19]
4 areturn
小編推薦一個學JAVA的學習裙【 一三三,九三零,六九三】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多干貨和技術資料分享Line numbers:
[pc: 0, line: 1]
其實在字節碼中 T 真的只是 Object。這很好理解。合成的橋方法實際是由編譯器生成的,因為 Parent.x() 簽名中的返回類型在實際調用的時候正好是 Object。在沒有這種橋方法的情況下引入泛型將無法在二進制下兼容。因此,改變 JVM 來允許這個特性所帶來的痛苦會更小(副作用是允許協變凌駕于一切之上) 很聰明,不是嗎?
Target Type 目標類型
Java Compiler 會根據你指定的目標類型來推斷(infers)出method該返回哪種類型的結果,例如:
Collections.emptyList
static List emptyList(); //這個方法沒有參數,只有一個T類型的返回類型,那么我不能傳入參數這個方法是如何知道用什么返回類型的呢,這就是target type
List listOne = Collections.emptyList();小編推薦一個學JAVA的學習裙【 一三三,九三零,六九三】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多干貨和技術資料分享
listOne是一個List類型的變量,Java Compiler會根據這個目標類型來推斷出emptyList method應該返回這個類型,這種類型推斷依賴于assignment context,也就是說我要賦給哪個變量,它是什么類型我就返回什么類型。
一句話總結就是:Java 恰好是一種看起來神秘的語言,其實不然。