java底层原理书籍_阿里面试题:Java中this和super关键字的底层实现原理
知道的越多,不知道的就越多,業(yè)余的像一棵小草!
編輯:業(yè)余草
來源:https://www.xttblog.com/?p=5028
B 站:業(yè)余草
最近一個粉絲加我說,接到了阿里的面試,問問我阿里會面試哪方面的東西。我說,阿里的套路基本上是,你會什么就問你什么,直到問得你懷疑人生。正所謂,你知道的越多,不知道的就越多,業(yè)余的像一顆小草!
今天,我們就一起來討論一個這個網友遇到的阿里面試題,Java 中 this 和 super 關鍵字的底層實現(xiàn)原理!文章后面附了一個我錄制的視頻,大家忽略!
眾所周知,在 Java 中,this 具有以下含義。
- 在 Java 中,每當一個對象創(chuàng)建后,Java 虛擬機都會給這個對象分配一個指向自身的引用,也就是 this。同時如果對象是子類對象,則還會有一個 super 引用指向當前對象的父類對象。
- 在類的方法定義中使用 this 關鍵字,表示使用該方法的對象的引用。
- 在一個類中,this 可以表示該類的當前實例。
- this 是對當前類對象的引用,對象只有被實例化才存在。
根據(jù) this 的這些含義,面試官就想知道 this 是怎么出來的?先看下面的代碼。
public?class?Xttblog?{????private?String?name;
????public?void?setName(String?name){
????????this.name?=?name;
????}
????public?static?void?main(String[]?args)?{
????????Xttblog?xttblog?=?new?Xttblog();
????????xttblog.setName("業(yè)余草");
????}
}
在 setName 方法中,可以使用 this 的本質是:編譯器在調用某個實例方法時,實際上會把當前的實例對象的引用作為第一個參數(shù)傳遞給方法。
經過編譯器的處理,xttblog.setName(“業(yè)余草”) 這行代碼實際上變成 xttblog.setName(xttblog,”業(yè)余草”)。而如果想從方法內部獲取當前對象的引用,就有一個專門的關鍵字 this,表示“調用方法的那個對象”的引用(如 xttblog)。
這一點,我能想到有 3 種方法來驗證它。
第一種是我們通過 Bytecode 工具查看字節(jié)碼的時候,會發(fā)現(xiàn)有 setName 方法有兩個 LOCALVARIABLE,即兩個局部變量,一個是 String 的,一個是 Xttblog 對象。
OCALVARIABLE?args?[Ljava/lang/String;?L0?L3?0LOCALVARIABLE?xttblog?Lcom/xttblog/Xttblog;?L1?L3?1
第二種就更簡單了,我們給 setName 方法在第一位再加一個 Xttblog this 參數(shù),你會發(fā)現(xiàn)編譯器不會報錯,方法調用都能夠成功。
public?class?Xttblog?{????private?String?name;
????public?void?setName(Xttblog?this,String?name){
????????this.name?=?name;
????}
????public?static?void?main(String[]?args)?{
????????Xttblog?xttblog?=?new?Xttblog();
????????xttblog.setName("業(yè)余草");
????}
}
第三種驗證方法,我們借助 Java8 提供的函數(shù)接口來驗證。比如下面的代碼。
public?class?Xttblog?{????private?String?name?=?"業(yè)余草";
????private?String?sayStr;
????public?void?setName(String?name){
????????this.name?=?name;
????}
????private?String?say(String?sayStr){
????????this.sayStr?=?sayStr;
????????return?this.name?+?"?say?:?"?+?this.sayStr;
????}
????public?static?void?main(String[]?args)?{
????????Xttblog?xttblog?=?new?Xttblog();
????????xttblog.setName("業(yè)余草");
????????BiFunction?function?=?Xttblog::say;
????????String?str?=?function.apply(xttblog,?"hello~");
????????System.out.println(str);
????}
}
以 BiFunction 為例,它要求的是以兩個輸入參數(shù),一個輸出參數(shù)。而我們調用的 say 只需要一個字符串類型的輸入參數(shù),但是我們的示例代碼中,卻傳遞了兩個參數(shù)。一個是 Xttblog 類型,一個是 String 類型,編譯器沒有報錯,可以正常執(zhí)行。
這也驗證了 this 的底層實現(xiàn)原理。
同理,super 的本質是:當我們 new 一個子類對象的時候,子類除了生成一個 this 引用指向自身,還會生成一個指向其直接父類對象的引用 super。如果子類在繼承父類的非私有的法和成員變量時,沒有同名的方法和變量,可以直接通過名稱使用父類的方法和變量。如果子類存在與父類同名的方法和成員變量時,要想區(qū)別訪問父類和自身的變量和方法,需要使用 super 關鍵字調用父類的方法和屬性。
這些在字節(jié)碼中都有體現(xiàn)。以下面的代碼為例:
public?class?Codedq?extends?Xttblog{????private?String?skill;
????public?void?setSkill(String?skill){
????????this.skill?=?skill;
????????System.out.println(super.say("hello?world"));
????????System.out.println(super.getName()?+?"會:"?+?this.skill);
????}
}
我們在字節(jié)碼中會看到,在 Codedq 的構造函數(shù)中,調用了父類 init 方法。
public?()V???L0
????LINENUMBER?9?L0
????ALOAD?0
????INVOKESPECIAL?com/xttblog/Xttblog.?()V
????RETURN
???L1
????LOCALVARIABLE?this?Lcom/xttblog/Codedq;?L0?L1?0
????MAXSTACK?=?1
????MAXLOCALS?=?1
注意上面的 INVOKESPECIAL 指令。super 關鍵字的底層原理就是靠 INVOKESPECIAL 指令。
在 Codedq 的代碼中,super 就是靠 INVOKESPECIAL 指令來調用父類方法的。
invokespecial 指令的主要作用是,用于調用一些需要特殊處理的實例方法,包括實例初始化方法、私有方法和父類方法。(Invoke instance method; special handling for superclass, private, and instance initialization method invocations )。
最后,我們來個簡單的總結,this 的底層實現(xiàn)是默認傳值,super 是靠 INVOKESPECIAL 指令。
?以上內容,若有疑問,歡迎公眾號評論區(qū)留言指正!
?總結
以上是生活随笔為你收集整理的java底层原理书籍_阿里面试题:Java中this和super关键字的底层实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql job_MySQL数据传输中
- 下一篇: 公积金贷款50万20年月供多少