1. 程式人生 > >深入理解JAVA多型原理

深入理解JAVA多型原理

  之前一直知道多型是什麼東西,平時敲程式碼也經常用到多型,但一直沒有真正瞭解多型底層的執行機制到底是怎麼樣的,這兩天才研究明白點,特地寫下來,跟各位同學一起進步,同時也希望各位大神指導和指正。

  多型的概念:同一操作作用於不同物件,可以有不同的解釋,有不同的執行結果,這就是多型,簡單來說就是:父類的引用指向子類物件。下面先看一段程式碼

 1 package polymorphism;
 2 
 3 class Dance {
 4     public void play(){
 5         System.out.println("Dance.play");
6 } 7 public void play(int i){ 8 System.out.println("Dance.play" + i); 9 } 10 } 11 12 class Latin extends Dance { 13 public void play(){ 14 System.out.println("Latin.play"); 15 } 16 public void play(char c){ 17 System.out.println("Latin.play" + c);
18 } 19 } 20 class Jazz extends Dance { 21 public void play(){ 22 System.out.println("Jazz.play"); 23 } 24 public void play(double d){ 25 System.out.println("Jazz.play" + d); 26 } 27 } 28 public class Test { 29 public void perform(Dance dance){ 30 dance.play();
31 } 32 public static void main(String[] args){ 33 new Test().perform(new Latin()); // Upcasting 34 } 35 }
View Code

  執行結果:Latin.play。這個時候你可能會發現perform()方法裡面並沒有類似“if 引數型別 = Dance/Latin”這樣的判斷,其實這就是多型的特性,它消除了型別之間的耦合關係,令我們可以把一個物件不當做它所屬的特定型別來對待,而是當做其基類的型別來對待。因為上面的Test程式碼完全可以這麼寫:

 1 public class Test {
 2     public void perform(Latin dance){
 3         dance.play();
 4     }
 5     public void perform(Jazz dance){
 6         dance.play();
 7     }
 8     public static void main(String[] args){
 9         new Test().perform(new Latin()); // Upcasting
10     }
11 }
View Code

但是這樣你會發現,如果增加更多新的類似perform()或者自Dance匯出的新類,就會增加大量的工作,而通過比較就會知道第一處程式碼會佔優勢,這正是多型的優點所在,它改善了程式碼的組織結構和可讀性,同時保證了可擴充套件性。

  那麼到底JVM是怎麼指向Latin類中play()的呢?為了解決這個問題,JAVA使用了後期繫結的概念。當向物件傳送訊息時,在編譯階段,編譯器只保證被呼叫方法的存在,並對呼叫引數和返回型別進行檢查,但是並不知道將被執行的確切程式碼,被呼叫的程式碼直到執行時才能確定。拿上面程式碼為例,JAVA在執行後期繫結時,JVM會從方法區中的Latin方法表中取到Latin物件的直接地址,這就是真正執行結果為什麼是Latin.play的原因,在解釋方法表之前,我們先了解一下繫結的概念。

  將一個方法呼叫同一個方法主體關聯起來被稱作繫結,JAVA中分為前期繫結和後期繫結(動態繫結或執行時繫結),在程式執行之前進行繫結(由編譯器和連線程式實現)叫做前期繫結,因為在編譯階段被呼叫方法的直接地址就已經儲存在方法所屬類的常量池中了,程式執行時直接呼叫,具體解釋請看最後參考資料地址。後期繫結含義就是在程式執行時根據物件的型別進行繫結,想實現後期繫結,就必須具有某種機制,以便在執行時能判斷物件的型別,從而找到對應的方法,簡言之就是必須在物件中安置某種“型別信”,JAVA中除了static方法、final方法(private方法屬於)之外,其他的方法都是後期繫結。後期繫結會涉及到JVM管理下的一個重要的資料結構——方法表,方法表以陣列的形式記錄當前類及其所有父類的可見方法位元組碼在記憶體中的直接地址

  動態繫結具體的呼叫過程為:

    1.首先會找到被呼叫方法所屬類的全限定名

    2.在此類的方法表中尋找被呼叫方法,如果找到,會將方法表中此方法的索引項記錄到常量池中(這個過程叫常量池解析),如果沒有,編譯失敗。

    3.根據具體例項化的物件找到方法區中此物件的方法表,再找到方法表中的被呼叫方法,最後通過直接地址找到位元組碼所在的記憶體空間。

  最後說明,域和靜態方法都是不具有多型性的,任何的域訪問操作都將由編譯器解析,因此不是多型的。靜態方法是跟類,而並非單個物件相關聯的。對動態繫結還有不明白的請看資料連結,個人感覺分析的很到位

相關推薦

深入理解JAVA原理

  之前一直知道多型是什麼東西,平時敲程式碼也經常用到多型,但一直沒有真正瞭解多型底層的執行機制到底是怎麼樣的,這兩天才研究明白點,特地寫下來,跟各位同學一起進步,同時也希望各位大神指導和指正。   多型的概念:同一操作作用於不同物件,可以有不同的解釋,有不同的執行結果,這就是多型,簡單來說就是:父類的引用

深入理解JAVA

何為多型,多型有什麼用,多型有什麼表現 多型是同一個行為具有多個不同表現形式或形態的能力。 比如說,你喜歡喝酒,你去酒店買酒讓服務員給你拿一瓶酒,這個時候服務員問你“要紅酒、白酒、洋酒”,這也是多型,下面給出一定程式碼演示 酒 a=new 洋酒(); 酒 a=new 紅酒(); 酒

深入理解java沒有烤山藥的存在,java就不香了嗎?

目錄 1、 從吃烤山藥重新認識多型 2、 多型前提條件【重點】 3、 多型的體現 4、 多型動態繫結與靜態繫結 5、 多型特性的虛方法(virtual) 7、 向上轉型

併發程式設計之美,帶你深入理解java執行緒原理

1.什麼是多執行緒? 多執行緒是為了使得多個執行緒並行的工作以完成多項任務,以提高系統的效率。執行緒是在同一時間需要完成多項任務的時候被實現的。 2.瞭解多執行緒 瞭解多執行緒之前我們先搞清楚幾個重要的概念! 如上圖所示:對我們的專案有一個主記憶體,這個主記憶體裡面存放了我們的共享變數、方法區、堆中的物件等

深入理解Java執行緒--synchronized的實現原理

執行緒安全是多執行緒程式設計中的一個重要的知識點,何為執行緒安全?在多執行緒併發中,有很多資料是執行緒共享的,當我們某個執行緒去操作共享資料的時候,需要先將共享資料複製到當前執行緒的記憶體空間中來,然後進行操作完畢之後再將資料更新到共享空間中去。這就造成了一個問題,當我們有多個執行緒去讀取和操作

深入理解Java信息(Class對象)與反射機制

成員變量 字段 機制 () 程序 轉換 默認 數據 統一   深入理解Class對象    RRTI的概念以及Class對象作用    認識Class對象之前,先來了解一個概念,RTTI(Run-Time Type Identification)運行時類型識別,對於這個詞一

深入理解 Java 線程核心知識:跳槽面試必備

java多線程多線程相對於其他 Java 知識點來講,有一定的學習門檻,並且了解起來比較費勁。在平時工作中如若使用不當會出現數據錯亂、執行效率低(還不如單線程去運行)或者死鎖程序掛掉等等問題,所以掌握了解多線程至關重要。本文從基礎概念開始到最後的並發模型由淺入深,講解下線程方面的知識。概念梳理本節我將帶大家了

深入理解Java

標記 err data oid 技術 with 引用 並不是 hashmap 泛型是什麽 一說到泛型,大夥肯定不會陌生,我們代碼裏面有很多類似這樣的語句: List<String> list=new ArrayList<>(); ArrayLi

java基礎學習總結(九):深入理解Java

一、什麼是泛型         “泛型” 意味著編寫的程式碼可以被不同型別的物件所重用。泛型的提出是為了編寫重用性更好的程式碼。泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。 比如常見的集合類 LinkedList: publi

深入理解java執行緒(六)

關於java多執行緒的概念以及基本用法:java多執行緒基礎 6,單例模式與多執行緒 如何使單例模式遇到多執行緒是安全的這是下面要討論的內容 6.1,立即載入 立即載入就是在使用類的時候已經將物件建立完畢,例如String s = new Stri

深入理解Java執行緒(五)

關於java多執行緒的概念以及基本用法:java多執行緒基礎 5,定時器Timer JDK中Timer類主要是負責計劃任務的功能,也就是在指定的時間開始執行某一個任務,封裝任務的類是TimerTask類,執行計劃任務的程式碼要放進TimerTask的子類,因為它一個抽象

深入理解Java執行緒(四)

關於java多執行緒的概念以及基本用法:java多執行緒基礎 4,Lock的使用 ReentrantLook類的使用 ReentrantReadWriteLock類的使用 4.1,ReentrantLook類的使用 新建MySe

深入理解Java執行緒(三)

關於java多執行緒的概念以及基本用法:java多執行緒基礎 3, 執行緒間通訊 執行緒在作業系統中是獨立的個體,經過特殊的處理,執行緒間可以實現通訊,進而成為一個整體,提高CPU利用率 3.1,等待/通知機制 等待:wait()方法作用是使當前執

深入理解Java執行緒(二)

關於java多執行緒的概念以及基本用法:java多執行緒基礎 2,多執行緒的同步 多個執行緒對同一物件的變數進行同時訪問時會引發執行緒的安全問題,即一個執行緒對一個變數修改後,其他執行緒可能會讀取到修改後的變數值,所以我們要對獲得的例項變數的值進行同步處理,保證其原子性

深入理解Java執行緒(一)

關於java多執行緒的概念以及基本用法:java多執行緒基礎 1,停止執行緒 停止執行緒意味著線上程執行完之前停止正在做的操作,即立刻放棄當前的操作,這並不容易。停止執行緒可以用Thread.stop()方法,但是這個方法不安全,所以不建議使用,還有一個方法就是Thre

Java 乾貨之深入理解Java

一般的類和方法,只能使用具體的型別,要麼是基本型別,要麼是自定義的類。如果要編寫可以應用多中型別的程式碼,這種刻板的限制對程式碼得束縛會就會很大。 ---《Thinking in Java》 泛型大家都接觸的不少,但是由於Java 歷史的原因,Java 中的泛型一直被稱為偽泛型,因此對Java中的泛型,有

深入理解Java執行緒--執行緒池(ThreadPool)

在java多執行緒開發中,我們需要使用執行緒的時候一般是建立一個Thread物件,然後呼叫start()方法去執行執行緒操作。這樣做沒有什麼問題,但是如果我們有很多工需要多個執行緒來非同步執行的時候,在我們建立了很多執行緒的情況下,會造成很大的效能方面的問題。 1.大量的執行緒的建立和銷燬,

深入理解 Java

首先提個問題: Java 泛型的作用是什麼?泛型擦除是什麼?泛型一般用在什麼場景? 如果這個問題你答不上來,那這篇文章可能就對你有些價值。 讀完本文你將瞭解到: 什麼是泛型 泛型是Java SE 1.5 的新特性,《Jav

Java基礎11———深入理解Java

Java泛型 why need 泛型? 首先,我們看下下面這段簡短的程式碼: public class GenericTest { public static void main(String[] args) { List list = new Arra

【學習筆記】 唐大仕—Java程式設計 第5講 深入理解Java語言之5.2 及虛方法呼叫

/** * 多型及虛方法呼叫 * @author cnRicky * @date 2018.11.7 */ 多型 多型(Polymorphism)是指一個程式中相同的名字表示不同的含義的情況 多型有兩種情形 編譯時多型:  *過載(Overload)(多個同名的不同方法)  *如 p.sayH