05.31 你不知道的Java系列,這幾件事你一定要知道!

程序員最重要的是思想,知其然知其所以然。

作為尚學堂的一員小編想問,你從一開始就在使用Java嗎?你是否還記得Java被稱作為”Oak”的時期?那時,面向對象仍然是一個熱門的話題,使用C++的人們都認為Java沒有任何機會,Applets 也只是一件事情。

你不知道的Java系列,這幾件事你一定要知道!

重載僅返回類型不同的方法

這樣的代碼無法編譯,對不?

class Test {

Object x() { return "abc"; }

String x() { return "123"; }

}

對。 Java 語言不允許兩個方法在同一個類中“等效重載”,而忽略其諸如throws自居或返回類型等的潛在的差異。

查看 Class.getMethod(String, Class…) 的 Javadoc。 其中說明如下:

你不知道的Java系列,這幾件事你一定要知道!

請注意,類中可能有多個匹配方法,因為 Java 語言禁止在一個類聲明具有相同簽名但返回類型不同的多個方法,但 Java 虛擬機並不是如此。虛擬機中增加的靈活性可以用於實現各種語言特徵。例如,可以用橋接方法實現協變參返回; 橋接方法和被重寫的方法將具有相同的簽名但擁有不同的返回類型。

你不知道的Java系列,這幾件事你一定要知道!

哇哦,有道理。實際上下面的代碼暗藏著很多事情:

abstract class Parent {

abstract T x();

}

class Child extends Parent<string> {/<string>

@Override

String x() { return "abc"; }

}

你不知道的Java系列,這幾件事你一定要知道!

來看看為 Child 生成的字節碼:

// Method descriptor #15 ()Ljava/lang/String;

// Stack: 1, Locals: 1

java.lang.String x();

0 ldc <string> [16]/<string>

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

Line numbers:

[pc: 0, line: 1]

其實在字節碼中 T 真的只是 Object。這很好理解。

你不知道的Java系列,這幾件事你一定要知道!

合成的橋方法實際是由編譯器生成的,因為 Parent.x() 簽名中的返回類型在實際調用的時候正好是 Object。在沒有這種橋方法的情況下引入泛型將無法在二進制下兼容。因此,改變 JVM 來允許這個特性所帶來的痛苦會更小(副作用是允許協變凌駕於一切之上) 很聰明,不是嗎?

你不知道的Java系列,這幾件事你一定要知道!

Target Type 目標類型

Java Compiler 會根據你指定的目標類型來推斷(infers)出method該返回哪種類型的結果,例如:

Collections.emptyList

static List emptyList(); //這個方法沒有參數,只有一個T類型的返回類型,那麼我不能傳入參數這個方法是如何知道用什麼返回類型的呢,這就是target type

List<string> listOne = Collections.emptyList(); /<string>

listOne是一個List<string>類型的變量,Java Compiler會根據這個目標類型來推斷出emptyList method應該返回這個類型,這種類型推斷依賴於assignment context,也就是說我要賦給哪個變量,它是什麼類型我就返回什麼類型。/<string>

你不知道的Java系列,這幾件事你一定要知道!

一句話總結就是:Java 恰好是一種看起來神秘的語言,其實不然。


分享到:


相關文章: