“面向对象对于程序语言的重要性就相当于内燃机对于工业界。–薛鹏”。这句话是我说的,你们要是想引用的话,请随意。面向对象将实例的状态,以及对状态的操作进行封装,使得它们彼此操作方便又对其他对象隔离。这是我们可以构建大型复杂系统的基石。

类的定义

class SayHi{
  private val hi = "Hi"
  def hiString(name:String)=hi+" "+name
}
val sayHi =new SayHi
sayHi.hiString("Mark")

命令行里的不太适合编写class,我建议大家从现在可以开始使用IDE了。Scala里默认的成员变量和方法都是public的。对外部总是可见。你可以加上private来限制外部访问。

单例对象

你可能听过单例模式,也可能在Java里自己实现过并且还和纠结过怎么实现才是线程安全的。但是这些在Scala里你不用再考虑了。只要把需要单例模式的类定义关键字从class 变成 object 就可以了。比如我们想做一个计数器,在整个程序里,它应该是唯一的。

object Counter{
  private var number = 0;
  def next()={number+=1;number}
}
Counter.next   //res0: Int = 1
Counter.next   //res1: Int = 2

我们讲了这么久还没讲到怎么定义一个程序入口main函数,为了避免你开始怀疑你看的是一个假的教程,我们马上就来讲main函数,还要输出一个Hello World!
因为我们知道main函数作为一个程序的入口点,它是唯一的,静态的。所以在Scala里,一个程序的入口点必须被定义在单例对象里。main函数的输入参数是一个Array[String],返回值是Unit。

object MyApp {
    def main(args:Array[String]): Unit = {
      println("Hello World!")
    }
}

好了这下有了Hello World了。

类的构造函数

在Scala里类的构造函数比Java要简洁

class Animal(category:String,name:String,age:Int) {
  def introduction():String={s"I'm $name and I'm $age years old."}
}

Java通过让构造函数和类同名来避免让用户定义方法和构造函数冲突,Scala在这里又进了一步,直接在类名后边加上方法签名来达到构造函数功能。那构造函数的函数体在哪呢?答案是类的代码块里除了成员变量和成员函数定义外的代码都是!也就是你可以在类的定义代码块里写语句了。类定义的代码块其实就是主构造函数。如果类的定义代码块里定义的val/var都是类的成员变量,那么通过类的构造函数传进来的参数呢?它们是类的成员变量吗?Scala把这个控制权给了你。规则就是如果在构造函数的参数列表里的参数名前什么都不加,那这个参数就不是类的成员变量。如果你加上了var/val,那么它同时就是类的var/val成员变量。我们看一个例子:

class Woman(val name:String,var mood:String,weight:Double) {
  val myWeight=weight*0.6
  def whoAreYou=s"I'm $name,I'm $mood,and I'm $myWeight KGs.."
}

很开心,这个例子实在太好了,我们定义女人这个类,这个类的构造函数里有3个参数,姓名:name,它是val的,心情:mood,它var的,体重:weight这个参数前边没有加val/var。
对于Woman的一个对象:

  • name 可以读,但是不可修改
  • mood 可以读,也可以随时修改
  • weight 不可见

那么weight是不是private的成员变量呢?答案是视情况而定,如果你定义的类的方法里访问了weigth,那么scala会把weight转化为private的类成员变量。如果你没有在类的成员方法里访问weight,那么weight就不会被转化为类的成员变量。

    val woman=new Woman("Lily","happy",100)
    val name = woman.name //可以读,不能写
    //val wight = woman.weight //不能访问
    println(woman.whoAreYou) //I'm Lily,I'm happy,and I'm 60.0 KGs..
    woman.mood="not happy" //女人当然可以随时修改心情
    println(woman.whoAreYou) //I'm Lily,I'm not happy,and I'm 60.0 KGs..

类的辅助构造函数

如果你想有多个构造函数,但是类只有一个语句块,那么我们就用this关键字来做方法名

class Woman(val name:String,var mood:String,weight:Double) {
  val myWeight=weight*0.6
  def whoAreYou=s"I'm $name,I'm $mood,and I'm $myWeight KGs.."
  def this(name:String="New Woman",weight:Double=50){
    this(name,"Happy",weigth)
  }
}

可以看到上边定义了一个辅构造方法,这个构造函数只会构造Happy的Woman,而且这个构造方法的参数有默认值。所有方法的参数都可以有默认值。通过上边这个辅助构造方法,我们可以有一下几种构造方式:

    woman = new Woman()
    woman = new Woman("CoCo")
    woman = new Woman(weight=20)

在利用默认参数时需要注意的就是,如果你不是按照方法参数列表顺序指定参数值的话,你需要给出参数名字。

伴生类/伴生对象

如果一个单例对象和一个类同名,那么这一对同名的类和对象就是伴生的。类叫做同名单例对象的伴生类,单例对象叫做同名类的伴生对象。它们的关系如此亲密,以至于他们要被定义在同一个文件里。我们回想一下Java里的静态变量和静态方法,它们被放在类的定义里,但是却不属于某一个具体的对象。这个对象不是一个纯粹的对象。Scala在这里更加纯粹。类里边的属性和方法是属于每一个实例化后的对象的。而伴生对象里,注意它也是一个对象,只是单例的。这个单例对象保存和它同名类的静态方法和静态属性。

class People(val name){
  val legs=name+" have "+People.legsNum+" legs." //这里访问了伴生对象里的私有变量。
}
object People{
  private val legsNum:Int=2
}
val people = new People("Colin")
println(people.legs)        //Colin have 2 legs.

伴生对象和伴生类的关系亲密到可以彼此访问对象的私有变量和方法的程度。伴生对象一般可以用来作为伴生类的工厂类。就像我们之前看到集合类型里Array和List一样。
我们写的

val list = List(1,2,3) //List.apply(1,2,3)

我们并没有new 关键字。这里其实我们调用的是List的伴生对象的apply方法。Scala里的apply方法,使得对象被像函数一样的调用。我们给我们的People伴生对象来定义一个apply方法,并用它返回一个People的对象。

  def apply(name:String): People ={
    new People(name)
  }

有了这个定义,我们就可以像这样来获得一个People对象了。

   val people =People("Mark") //不再需要new 关键字了。
    println(people.legs)

发表评论

电子邮件地址不会被公开。 必填项已用*标注

%d 博主赞过: