Java中,由this關鍵字引起的問題

  好久以前一直有一個疑問,最近從新翻了遍JVM的書,纔算是終於有所頓悟。問題以下:java

被本身遺忘的問題

 1 package org.hanyan.test.testClass;
 2 
 3 public class T3AboutThis {
 4     public static void main(String[] args) {
 5         new SubT3().func();
 6         SuperT3 s = new SuperT3();
 7         System.out.println(s instanceof SubT3);//false
 8     }
 9 }
10 
11 class SuperT3 {
12     public String name = "Jack";
13     
14     protected void func() {
15         System.out.println(this.name);//Jack
16         System.out.println(this instanceof SuperT3);//true
17         System.out.println(this instanceof SubT3);//true
18     }
19 }
20 class SubT3 extends SuperT3 {
21     public String name = "Peter";
22 }

一直沒搞明白,上述代碼中第17行爲何打印出來的true。jvm

javap 打印了SuperT3類編譯後的字節碼指令以下:this

第1三、23字節的指令均爲同一個引用變量,這個引用變量咱們能夠在本地變量表中看到是Lorg/hanyan/test/testClass/SuperT3,spa

這裏搞不明白爲何1四、24字節的instanceof指令會返回一樣的結果:truecode

目前懷疑是在運行中,jvm將本地變量this替換了。但這又引出一個問題,爲何this.name中的this沒有被替換?這個替換規則是怎麼樣的?blog

我自認爲還算比較準確的答案

其實這個現象中有兩個點須要說明:get

1.關於17行爲何會打印出true?虛擬機

這個是虛擬機字節碼指令invokevirtual的動態查找過程的表現。編譯

1三、23字節的指令的參數均爲同一引用Lorg/hanyan/test/testClass/SuperT3,這裏我以前理解的不深入,其實這裏的引用是「符號引用」,指SuperT3類常量池中的某個CONTANT_Methodref_info類型的「符號引用」。但虛擬機執行引擎在運行期執行這個字節碼指令時,首先會查找這條指令的接收者(調用者)的實際類型,而後再肯定真正的「直接引用」指向哪裏。這個解析操做實現了方法的動態分派,也就是咱們常說的「方法重寫」。(具體「符號引用」解析爲「直接引用」的解釋請參考java的動態解析)。因此1三、23的字節碼指令的接收者實際是SubT3,即返回true。class

那麼就會引出第二個關注點,代碼的15行爲何是「Jack」?

2.代碼的15行爲何是「Jack」?

虛擬機字節碼指令getfeild,與invokevirtual不一樣,不存在動態查找過程。因此,getfeild字節碼指令的參數爲當前類的常量池的「符號引用」,此時的「符號引用」已在類加載過程當中的「解析」階段轉化爲「直接引用」,即表示當前類的變量name的值,因此返回「Jack」。


至此,整個解釋完畢。

總結,this關鍵字也只是在編譯好的字節碼文件中,方法的第一個參數(方法的接收者)的訪問符而已。整個問題的重點應該關注虛擬機如何執行這些字節碼指令。

相關文章
相關標籤/搜索