學習設計模式的時候,發現不少模式都用到了向上轉型(eg. 工廠方法)。而我對向上轉型(upcasting)的機制並不十分熟悉。這篇文章將深刻分析向上轉型的機制、內存分析。設計模式
先從幾個基本概念開始:學習
Java中的數據類型分爲兩類:基本數據類型(int, double)和引用類型(String)。引用類型對象中保存着一個地址(稱爲「引用」),引用指向實際對象(稱爲「實例」),實際對象中保存着值。spa
關於Java數據類型在內存中的分析詳解,請參考知友Intopass的解答:設計
Java 究竟是值傳遞仍是引用傳遞? - Intopass的回答 - 知乎
https://www.zhihu.com/questio...
Heap中的對象會繼續指向內存中的數據段(data segment)。數據保存對象的實際值code
定義:將父類的引用指向子類的實例 or 將子類對象賦值給父類引用對象
Dog dog = new Dog(); Animal anim = (Animal) dog; //實際對象類型沒變,僅引用類型改變了 anim.eat();
因爲實際對象類型沒變,因此,anim調用的eat方法還是Dog類中重寫的eat方法,而不是父類Animal類中的eat方法。內存
咱們爲何要使用向上轉型?get
Generally, upcasting is not necessary. However, we need upcasting when we want to write general code that deals with only the supertype.
通常說來,向上轉型不是必須的。但有時候,當咱們的代碼只須要與父類打交道時,能夠使用向上轉型,來使咱們的代碼不依賴具體子類,好比:it
public class AnimalTrainer { public void teach(Animal anim) { anim.move(); anim.eat(); } }
如下代碼,teach方法能夠接受Animal類的任意子類:io
Dog dog = new Dog(); Cat cat = new Cat(); AnimalTrainer trainer = new AnimalTrainer(); trainer.teach(dog); trainer.teach(cat);
咱們來分析如下轉型代碼在內存中的表示:
Dog dog = new Dog(); Animal anim = (Animal)dog;