手拉手教你實(shí)現(xiàn)一門編程語(yǔ)言 Enkel, 系列 16

本文系 Creating JVM language 翻譯的第 16 篇坦康。
原文中的代碼和原文有不一致的地方均在新的代碼倉(cāng)庫(kù)中更正過(guò)攻泼,建議參考新的代碼倉(cāng)庫(kù)火架。

源碼

Github

OOP 和 statics

面向?qū)ο笳Z(yǔ)言中最大的優(yōu)點(diǎn)是啥?我個(gè)人認(rèn)為是多態(tài)忙菠, 如何實(shí)現(xiàn)多態(tài)距潘,使用繼承唄,可以在靜態(tài)語(yǔ)義下使用繼承么只搁?肯定不行呀音比。

在我認(rèn)為,靜態(tài)語(yǔ)義違反了面向?qū)ο蟮乃枷肭馔铮粦?yīng)該出現(xiàn)在面向?qū)ο笾卸呆妫瑸榱吮苊馐褂枚鄳B(tài)稽犁,你可以用單例呀。

因此骚亿,為何有 static 情況下已亥,Java 還聲稱自己是面向?qū)ο蟮哪兀课艺J(rèn)為来屠,Java 是為了迎合 C++ 更加方便的接納 Java 才引入的歷史因素虑椎。

去掉 static

直到上一篇博客,Enkel 中一直存在 static俱笛。包括 main 方法和其他的靜態(tài)方法捆姜,這么是為了方便實(shí)現(xiàn)語(yǔ)言的其他特性,比如變量迎膜,條件表達(dá)式泥技,循環(huán),方法調(diào)用磕仅,然后才轉(zhuǎn)成 OO珊豹。

那么我們來(lái)實(shí)現(xiàn)沒(méi)有靜態(tài)的 OO 吧。

main 方法

static main 方法需要 Java 程序員手動(dòng)編寫(xiě)榕订。Enkel 是這樣處理的:

  • 編譯器自動(dòng)生成
  • 在 main 方法中店茶,用默認(rèn)的構(gòu)造器創(chuàng)建一個(gè)對(duì)象
  • 然后調(diào)用 start 方法
  • 程序員需要提供 start 方法定義
private Function getGeneratedMainMethod() {
     FunctionParameter args = new FunctionParameter("args", BultInType.STRING_ARR, Optional.empty());
     FunctionSignature functionSignature = new FunctionSignature("main", Collections.singletonList(args), BultInType.VOID);
     ConstructorCall constructorCall = new ConstructorCall(scope.getClassName());
     FunctionSignature startFunSignature = new FunctionSignature("start", Collections.emptyList(), BultInType.VOID);
     FunctionCall startFunctionCall = new FunctionCall(startFunSignature, Collections.emptyList(), scope.getClassType());
     Block block = new Block(new Scope(scope), Arrays.asList(constructorCall,startFunctionCall));
     return new Function(functionSignature, block);
 }

start 方法是非靜態(tài)的,但其實(shí)是 main 方法的一種變體劫恒。

INVOSTATIC vs INVOKEVIRTUAL

在第七部分忽妒,我用了 INVOKESTATIC 來(lái)做方法調(diào)用,是時(shí)候換成 INVOKEVIRTUAL 了兼贸。

INVOKEVIRTUAL 有一點(diǎn)和 INVOKESTATIC 有很大的差異段直,INVOKEVIRTUAL 需要一個(gè)所有者,INVOKESTATIC 從棧中出棧參數(shù)溶诞,INVOKEVIRTUAL 首先是把所有者出棧鸯檬,然后才是出棧參數(shù)。

如果沒(méi)有顯示的提供所有者信息螺垢,默認(rèn)用 this喧务。


//Mapping antlr generated FunctionCallContext to FunctionCall 
@Override
public Expression visitFunctionCall(@NotNull EnkelParser.FunctionCallContext ctx) {
    //other stuff
    boolean ownerIsExplicit = ctx.owner != null;
    if(ownerIsExplicit) {
        Expression owner = ctx.owner.accept(this);
        return new FunctionCall(signature, arguments, owner);
    }
    ClassType thisType = new ClassType(scope.getClassName());
    return new FunctionCall(signature, arguments, new VarReference("this",thisType)); //pass "this" as a owner 
}
//Generating bytecode using mapped FunctionCall object
public void generate(FunctionCall functionCall) {
    functionCall.getOwner().accept(this); //generate owner (pushses it onto stack)
    generateArguments(functionCall);  //generate arguments
    String functionName = functionCall.getIdentifier();
    String methodDescriptor = DescriptorFactory.getMethodDescriptor(functionCall.getSignature());
    String ownerDescriptor = functionCall.getOwnerType().getInternalName();
    //Consumes owner and arguments off the stack
    methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, ownerDescriptor, functionName, methodDescriptor, false); 
}

示例

如下 Enkel 代碼:

HelloStart {

    start {
        print "Hey I am non-static 'start' method"
    }
}

生成字節(jié)碼:

public class HelloStart {
  public void start();
    Code:
       0: getstatic     #12                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #14                 // String Hey I am non-static  'start' method
       5: invokevirtual #19                 // Method "Ljava/io/PrintStream;".println:(Ljava/lang/String;)V
       8: return

  //Constructor
  public HelloStart();
    Code:
       0: aload_0   //get "this"
       1: invokespecial #22                 // Method java/lang/Object."<init>":()V - call super
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class HelloStart - create new object
       3: dup       //duplicate new object so that invokespecial does not consumes it
       4: invokespecial #25                 // Method "<init>":()V - call constructor
       7: invokevirtual #27                 // Method start:()V
      10: return
}

與之對(duì)應(yīng) Java 類如下:

public class HelloStart {
    public HelloStart() {
    }

    public static void main(String[] var0) {
        (new HelloStart()).start();
    }
    
    public void start() {
        System.out.println("Hey I am non-static \'start\' method");
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市枉圃,隨后出現(xiàn)的幾起案子功茴,更是在濱河造成了極大的恐慌,老刑警劉巖孽亲,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件坎穿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)玲昧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門栖茉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人孵延,你說(shuō)我怎么就攤上這事吕漂。” “怎么了尘应?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵惶凝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我犬钢,道長(zhǎng)苍鲜,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任娜饵,我火速辦了婚禮,結(jié)果婚禮上官辈,老公的妹妹穿的比我還像新娘箱舞。我一直安慰自己,他們只是感情好拳亿,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布晴股。 她就那樣靜靜地躺著,像睡著了一般肺魁。 火紅的嫁衣襯著肌膚如雪电湘。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,262評(píng)論 1 308
  • 那天鹅经,我揣著相機(jī)與錄音寂呛,去河邊找鬼。 笑死瘾晃,一個(gè)胖子當(dāng)著我的面吹牛贷痪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蹦误,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼劫拢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了强胰?” 一聲冷哼從身側(cè)響起舱沧,我...
    開(kāi)封第一講書(shū)人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎偶洋,沒(méi)想到半個(gè)月后熟吏,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡玄窝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年分俯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了肾筐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡缸剪,死狀恐怖吗铐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杏节,我是刑警寧澤唬渗,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站奋渔,受9級(jí)特大地震影響镊逝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嫉鲸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一撑蒜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧玄渗,春花似錦座菠、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至岁钓,卻和暖如春升略,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屡限。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工品嚣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钧大。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓腰根,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拓型。 傳聞我的和親對(duì)象是個(gè)殘疾皇子额嘿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類相關(guān)的語(yǔ)法劣挫,內(nèi)部類的語(yǔ)法册养,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法压固,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,662評(píng)論 18 399
  • 第6章類文件結(jié)構(gòu) 6.1 概述 6.2 無(wú)關(guān)性基石 6.3 Class類文件的結(jié)構(gòu) java虛擬機(jī)不和包括java...
    kennethan閱讀 938評(píng)論 0 2
  • 成長(zhǎng)就像是一片郁蔥的森林球拦。里面有讓人喜愛(ài)的草林;有讓人恐懼的兇猛怪獸;也有迷惑我們的櫻樹(shù)花坎炼。一旦進(jìn)入這座森林愧膀,就會(huì)...
    涼字拖閱讀 132評(píng)論 0 0
  • 你以為你有很多路可以選擇,但是在你周圍有很多看不見(jiàn)的墻谣光。 ——今何在 山桃熟了幾次檩淋,海...
    y居合細(xì)雪閱讀 241評(píng)論 0 2
  • 1893年12月28日 新中國(guó)第一任大法官?gòu)堉咀屨Q辰 1895年12月28日 世界第一部電影誕生 1903年12月...
    逸香居主白龍閱讀 262評(píng)論 0 0