深入理解JAVA多態原理

来源:http://www.cnblogs.com/startRuning/archive/2016/07/15/5673485.html
-Advertisement-
Play Games

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


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

  多態的概念:同一操作作用於不同對象,可以有不同的解釋,有不同的執行結果,這就是多態,簡單來說就是:父類的引用指向子類對象。下麵先看一段代碼

 

 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.根據具體實例化的對象找到方法區中此對象的方法表,再找到方法表中的被調用方法,最後通過直接地址找到位元組碼所在的記憶體空間。

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

  參考資料:http://hxraid.iteye.com/blog/428891

 

 

 

 

 

 

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.兩個拷貝之間主要是用於對象之間的拷貝! 2.區別 沒指針: 深拷貝和淺拷貝沒什麼區別; 有指針: 淺拷貝:即對象的預設拷貝函數,只是將指針的地址拷貝給對象,兩個變數同時指向一個地址,這樣在析構的時候必然會導致程式崩潰; 深拷貝:即要自定義拷貝函數,將指針new一段新記憶體保存起來;這樣析構也不會崩 ...
  • 這是本學期java課中實驗大綱里的第一個實驗,這裡簡單做了一個無用戶界面版本。 能看到判斷對錯的方法運用了直接運算符計算結果與函數定義後的運算結果相比較,相等得分,不相等則不得分。 編程中出現的問題:在計算結果為小數的除法時,一開始會出現結果怎麼算都不對的情況,他的正確答案也是一個向偶舍入的數值,那 ...
  • 直接插入排序 直接插入排序是一種簡單的插入排序法,其基本思想是:把待排序的紀錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的紀錄插入完為止,得到一個新的有序序列。[1] 例如,已知待排序的一組紀錄是: 60,71,49,11,24,3,66 假設在排序過程中,前3個紀錄已按關鍵碼 ...
  • 最近遇到的關於VS里編譯出現的“無法解析的外部符號”問題,在網上尋求解決辦=辦法時查到下麵的博客內容,作者講解的挺全面的,作為收藏以備將來查詢。 原文http://blog.csdn.net/shenyulv/article/details/6699836 VC++時經常會遇到鏈接錯誤LNK2001 ...
  • 從誕生至今,20多年過去,Java至今仍是使用最為廣泛的語言。這仰賴於Java提供的各種技術和特性,讓開發人員能優雅的編寫高效的程式。今天我們就來說說Java的一項基本但非常重要的技術記憶體管理 瞭解C語言的同學都知道,在C語言中記憶體的開闢和釋放都是由我們自己來管理的,每一個new操作都要對於一個de ...
  • scalaz-stream庫的主要設計目標是實現函數式的I/O編程(functional I/O)。這樣用戶就能使用功能單一的基礎I/O函數組合成為功能完整的I/O程式。還有一個目標就是保證資源的安全使用(resource safety):使用scalaz-stream編寫的I/O程式能確保資源的安 ...
  • 項目里有各種加密方法,但從來沒有仔細研究過。一般只是copy。這幾天遇到一些問題,看了一下加密代碼,覺得有些疑惑。 我們知道jdk已經為我們包裝好了很多的演算法。但究竟包裝了哪些演算法,怎麼去掉這些演算法我並沒有去查過。今天跟了一下源碼,大概知道了。 首先要從下麵這幾行代碼說起: 對於AES加密,我們用K ...
  • 最近正在系統學習OpenCV,將不定期發佈筆記,主要按照毛星雲的《OpenCV3編程入門》的順序學習,會參考官方教程和文檔。學習工具是Xcode+CMake,會對書中一部分內容更正,並加入cmakelist的內容。 書中大部分內容來自OpenCV文檔,其實比較推薦官方文檔和教程 OpenCV2.4. ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...