深入剖析scala的App特质

今天一个朋友问我关于app特质调用的问题,我去花了点时间梳理了一下
我们先看App的源码

深入剖析scala的App特质_第1张图片

什么是App特质

trait App指的是scala.App,我们的单例对象混入这个特质就可以运行,而不必进行Main方法的定义,请看代码

    object Test1 {
      def main(args: Array[String]) {
        println("run")
          }
    }

    object Test2 extends App{
        println("also run")
    }

运行结果自然是都会打印对应内容,那么我们看看对Test2到底做了什么:
能这样做是因为App特质声明了带有合适签名的main方法,并被我们自己写的单例对象继承,使得能像scala程序一样,花括号之间的代码被收集进单例对象的主构造器,并在类初始化的时候执行。
这段话是scala编程的第45页关于Application的叙述

那么看我们模仿这个动作:

trait  MyApp{
println("I'm my app")
def main(args: Array[String]) {
    args.foreach(x =>    println(s"${System.currentTimeMillis()},$x"))
  }
}

先定义一个带有main函数的特质,在混入该特质时打印“I’m my app”
再把传入的参数依次打印,并加上时间戳

下面再来一个单例对象

    /**
  * Created by ctao on 2015/11/13.
  */
object MyTest extends MyApp{
  println("I'm Test")
  MyTest.main(Array("hello","world"))
  println(s"${System.currentTimeMillis()},in My Test")

}

在构建该单例对象的时候先打印“I’m Test”
再将参数传递给main
最后打印时间戳
深入剖析scala的App特质_第2张图片

结果表明先进入特质myapp,然后进入Test的第一句,再执行了main方法,最后打印了My Test

交换一下MyTest的中句子的次序:

/**
  * Created by ctao on 2015/11/13.
  */
object MyTest extends MyApp{
  println(s"${System.currentTimeMillis()},I'm Test")
  println(s"${System.currentTimeMillis()},in My Test")
  MyTest.main(Array("hello","world"))

}

trait  MyApp{
  println(s"${System.currentTimeMillis()},I'm my app")
  def main(args: Array[String]) {
    args.foreach(x => println(s"${System.currentTimeMillis()},$x"))
  }
}

再次观察结果:
深入剖析scala的App特质_第3张图片

证明了在运行中的顺序真的是我们第一次说的那样,先构建特质,而单例对象的运行是按照单例对象的语句的书写顺序执行调用的

接着我们交换特质中的main和打印

/**
  * Created by ctao on 2015/11/13.
  */
object MyTest extends MyApp{
  println(s"${System.currentTimeMillis()},I'm Test")
  println(s"${System.currentTimeMillis()},in My Test")
  MyTest.main(Array("hello","world"))

}

trait  MyApp{
  def main(args: Array[String]) {
    args.foreach(x => println(s"${System.currentTimeMillis()},$x"))
  }
  println(s"${System.currentTimeMillis()},I'm my app")
}

再次观察结果:
深入剖析scala的App特质_第4张图片

这里最先进入的还是“I’m my app”,说明是先完成了特质的构建,而main函数的位置则和单例对象的调用才有直接的关系。

Debug

观察一下debug值栈变化
深入剖析scala的App特质_第5张图片
深入剖析scala的App特质_第6张图片
结论:
在调用过程中特质先于单例对象构建,特质的main方法的调用和单例对象的调用有关,
我们可以通过单例对象.main(Array[String]())将参数传递给App特质

你可能感兴趣的:(scala,对象,app,scala)