在我們平時在java基礎學習到多態的時候我們知道一個父類引用指向子類對象的時候,編譯時看父類,運行時看子類。那麼抱着這個認識看下下面這個demo,以及給你帶來怎麼樣的思考?
public class Demo3 {
public static String classmodify(Set<?> s){
return "set";
}
public static String classmodify(List<?> s){
return "List";
}
public static String classmodify(Collection<?> s){
return "Collection";
}
public static void main(String[] args) {
Collection<?>[] collection={
new HashSet<String>(),
new ArrayList<BigDecimal>(),
new HashMap<String,String>().values()
};
for (Collection<?> collection2 : collection) {
System.out.println(classmodify(collection2));
}
}
}
打印
Collection
Collection
Collection
因爲要調用哪個重載是在編譯器做的決定,在for循環的三次中編譯時期的類型都是相同的Collection,每次迭代的運行時期的類型是不相同的,但這個不影響重載方法的選擇。
這個與我們多態的父類引用指向子類對象,編譯時看父類,運行時看子類不同的是,在重載的方法選擇過程中,對象的運行時類型並不影響哪個重載版本被執行,選擇工作是在編譯時期完成的,完全基於參數的編譯時期的類型。
但是多態的父類引用指向子類對象與這個不一樣的,舉個例子。
public class Fu {
String name(){
return "fu";
}
}
public class Zi extends Fu {
String name(){
return "zi";
}
}
public class Sun extends Zi {
String name(){
return "Sun";
}
}
public static void main(String[] args) {
ArrayList<Fu> list = new ArrayList<Fu>();
list.add(new Fu());
list.add(new Zi());
list.add(new Sun());
for (Fu item : list) {
System.out.println(item.name());
}
}
}
打印結果是:
fu
zi
Sun
原因
:儘管每次循環迭代過程中編譯時期的類型都是Fu,運行時是各自的類型,當調用被覆蓋的方法時,對象編譯時期的類型不影響哪個方法被執行
想要看這個引用的運行時類型
System.out.println(collection2 instanceof Set ?"set":collection2 instanceof List?"list":collection2 instanceof Collection<?>?"Collection<?>":"");