Scala专题系列(五):类与对象

2022-04-18 13:56:43 浏览数 (1)

Scala 是一个函数式编程语言,也是一个面向对象的编程语言,与 Java、 Python、 Ruby、Smalltalk 等其他语言一样,Scala 在架构层面上提倡的方法是:小处用函数式编程,大处用面向对象编程。用函数式实现算法、操作数据,以及规范地管理状态,是减少 bug、压缩代码行数和降低项目延期风险的最好方法。另一方面, Scala 的 OO 模型提供很多工具,可用来设计可组合、可复用的模块。这对于较大的应用程序是必不可少的。因此, Scala 将两者完美地结合在了一起。

一 : 类的声明与方法

Scala类的声明看上去和Java很相似

代码语言:javascript复制
class Person{
    private var value = 0 // 字段必须初始化
    def addAge(){ value  = 1 }  // 方法默认是public的
     def age() = value
}

在Scala中,类并不声明为public,类都具有公有可见性

使用类需要做的就是构造对象并按照通常的方式来调用方法:

val p = new Person

p.addAge()

println(p.age) // 在调用无参方法时,圆括号可以不写 一般对于修改值得方法加上圆括号,对于取值的方法可以不写圆括号

get/set 方法

类中的字段自动带有getter/setter方法。也可以用定制的getter/setter方法替换掉原来的字段的定义,而不必修改使用的客户端——这就是所谓的“统一访问原则”。

代码语言:javascript复制
class persion{
    var age = 0 // 声明age属性,默认生成get/set方法
    private[this] var privateName = "lisi" // private[this] 修饰的变量只能在当前类中使用
}

只带getter属性

如果需要一个只读属性,有getter但没有setter,属性的值在对象构建完成之后就不在改变,则可以使用val字段

代码语言:javascript复制
class person{
    val time = new Date // 生成一个final字段和一个getter方法,但没有setter
}

get/set汇总

1:var foo:scala自动生成一个getter和一个setter

2:val foo:scala自动合成一个getter

3:自己定义foo和foo_=方法

4:自定义foo方法

Bean属性

前面提到Sacla定义的字段提供了getter和setter方法,

当我们将scala字段标注为@BeanProperty时,这样的方法会自动,比如:

代码语言:javascript复制
class person{
    @BeanProperty var name:String = _ 
}

将会生成四个方法:

1.name:String

2:name=(newValue:String):Unit

3:getName():String

4:setName(newValue:String):Unit

类构造器

主构造器:

在Scala中,每个类都有一个主构造器,主构造器并不以this方法定义,而是与类定义在一起。

1.scala中,主构造器的参数直接放在类名后面

代码语言:javascript复制
class person(val name:String,val age:Int){
    …..
}

主构造器的参数被编译成自段,其值被初始化成构造时传入的参数,如上面的例子中,name和age成为person类的字段

2:主构造器会执行类定义中的所有语句

构造参数也可以是普通的方法参数,不带val或var,这样的参数如何处理取决于它们在类中如何被定义。

如果不带val或var的桉树至少被一个方法所使用,那么它将是字段

辅助构造器

和java一样,Scala也可以有任意多的构造器

1:辅助构造器的名称为this,在java中辅助构造器的名称与类名相同

2:每一个辅助构造器都必须以一个对先前已定义的其它辅助构造器或主构造器的调用开始

代码语言:javascript复制
class person{
    private var name=“”
    private var age = 0
    def this(name:String){
        this()
        this.name = name
    }
    def this(name:String,age:Int){
        this(name)
        this.age = age
    }
}

嵌套类

在scala中,几乎可以在任何语法结构中内嵌任何语法结构,可以在函数中定义函数,可以在类中定义类

代码语言:javascript复制
class Network{
    class member{
    }
}
val net = new NetWork
val nw = new NetWork

和在java中不同,每个实例都有它自己的member类,就和他们有自己member字段一样,在这里net.member 和nw.member 是不同的两个类

对象

在scala中没有静态方法或静态字段,我们可以用object这个语法结构来达到同样的目的,对象定义了某个类的单个实例,包含特性,比如:

代码语言:javascript复制
object Accounts{
    private var lastNumber = 0
}

我们在调用的时候,直接Accounts.newNum 即可

  1. 在Java中会使用单例对象的地方,在Scala中都可以用对象来实现
  2. 作为存放工具函数或常量的地方
  3. 高效的共享单个不可变实例
  4. 需要用单个实例来协调某个服务

伴生对象.

在集合那个篇章里面,有讲到一个val list = List("1","2") 其实这个内部就是一个伴生类,

在java中,会用到既有实例方法又有静态方法的类,在Scala中,可以通过类和与类名同名的"伴生"对象来达到同样的目的.比如:

代码语言:javascript复制
class Account{
    val id = Account.newNum 
    private var balace = 0.0
    def deposit(amount:Double){ balace  = amount }
}
object Account{  // 伴生对象
    private var lastNum = 0 
    private var newNum() = { lastNum  = 1 ; lastNum }
}

类可以和它的伴生对象相互访问私有特性,且必须是在同一个源文件中

再次回顾apply方法

通常,一个apply方法返回的是伴生类的对象

比如

Array对象定义了apply方法,让我们可以用下面这样的表达式来创建数组

Array("red","gree","yello")

这样我们就省去了构造器,也不用new出一个对象了

实例:

代码语言:javascript复制
class Acount private (val id :Int,balance:Double){
    private var balance = balace
}
object Acount{ // 伴生对象
    def apply(balace:Double) = {
        new Aount(newNum(),balace)
    }
}

这样我们在调用Acount的时候,可以直接

val account = Account(1000.0)

枚举

在Scalal中没有枚举类型,不过标准库中提供了一个Enumeration的一个助手类,可以用于产出枚举

比如:

定义一个扩展Enumeration类的对象并以Value方法调用初始化枚举中的所有可选值

代码语言:javascript复制
object Color extends Enumeration{
    val Red ,Yellow,Green = value
}

在上面我们定义了三个字段,Red,Yellow和Green,然后用Value调用将它们初始化,这是如下代码的简写

val Red = value

val Yellow = Value

val Green = Value

每次调用Value方法都返回内部类的新实例,该内部类也叫做Value

或者可以向Value方法传入ID,名称 或者两个都传

val Red = Value(0,"hongse")

val Yellow = Value(10) // 名称为 "Yellow" ID为10

val green = Value("gg") // ID 为11 名称为gg

如果不指定,则ID在将前一个枚举值基础上加1,从零开始.缺省名称为字段名

定义完之后,我们可以用Color.Red 这种方式来调用

0 人点赞