Scala進階之App特質


App特質的作用

App特質的作用那就是延遲初始化,從代碼上看它繼承自DelayedInit,里面有個delayedInit方法 trait App extends DelayedInit DelayedInit特質里定義了延遲初始化方法: def delayedInit(x: => Unit): Unit 開發者可以直接在初始化塊里寫邏輯,(這里指的是 extends App{//todo}里的//todo代碼) 然后編譯器會把這段初始化代碼塊里的邏輯封裝成一個函數對象(是(() => Unit)類型) override def delayedInit(body: => Unit) { initCode += (() => body) } 緩存起來(並沒有運行),然后放到一個集合(ListBuffer)中,之后在main方法里一行一行調用並執行, 所以只有在執行到main方法的時候才會觸發,從而達到延遲初始化的效果。 def main(args: Array[String]) = { ... for (proc <- initCode) proc() ... } 
不過在實際開發中,經常需要一開始就初始化,不然會報錯,如空指針異常,真正使用App的機會個人感覺都不多

object AppInternals extends App{
  def testApp{
    val c =new C
    println("3. Hello  spark")
  }
}

trait Helper extends DelayedInit{
   def delayedInit(body: => Unit)={
     println("1. dummy text, printed before inititalization of C")
     body  //evaluates the initialization code of C
   }
}

class C extends Helper{
   println("2. this  is the initialization code of C")
}

object AppTest {
    def main(args: Array[String]) {
    	AppInternals.testApp
    }
	
}

運行結果:

   1. dummy text, printed before inititalization of C

   2. this is the initialization code of C
   3. Hello spark

  

 

問題:  是怎么把封裝的初始化代碼塊傳給delayedInit(body: => Unit)的?

用反編譯工具jd-gui.exe把上面生成的.class反編譯出來,可以看到多出了好多個類, 
其中主要的有 
class AppInternals, delayedInitbody,AppInternals, C, delayedInitbody,Helper,Helperclass

delayedInit$body出現兩次,一次出現在AppInternals中,一次出現在C中, 它里面都有一個方法 
apply()

分別對應的是

public final Object apply()//AppInternals
    {
      this.$outer.c_$eq(new C());

      Predef..MODULE$.println("Hello Spark");

      return BoxedUnit.UNIT;
}

    public final Object apply() { //C
    Predef..MODULE$.println("this is the initialization code of C");

    return BoxedUnit.UNIT;
}

  

從第一個apply中可以看出它已經把例子代碼中的代碼塊封裝起來了 

object AppInternals extends App{ 
val c = new C 
println(“Hello Spark”) 
} 

  


從第二個apply可以看出它把C中的 

class C extends Helper { 
println(“this is the initialization code of C”) 
} 

  


代碼塊封裝起來了 
最后在class HelperclasspublicstaticvoiddelayedInit(Helperthis, Function0 body) 

{ 
Predef..MODULE$.println(“dummy text, printed before initialization of C”);

body.applymcVsp(); 
} 

  

 

這就是初始化代碼塊的執行順序,在main方法里調用delayedInit方法,先是執行 

Predef..MODULE$.println(“dummy text, printed before initialization of C”);

  

 

之后調用 body.applymcVsp();

body.applymcVsp()里先調用

this.outer.c_$eq(new C());

Predef..MODULE$.println(“Hello Spark”);

  

所以是先執行 this.outer.c_$eq(new C());

new C執行時就執行語句

println(“this is the initialization code of C”)

  

接着執行

println(“Hello Spark”);

  

所以輸出的結果就是這樣的

dummy text, printed before initialization of C 
this is the initialization code of C 
Hello Spark

  

補充內容是自己猜測的居多,不保證正確,個人覺得背后的原理其實不用深究,知道有這么回事就行了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM