vlambda博客
学习文章列表

Scala中的构造器与对象【文末加群学习哦】

前言

在《》中我们详细介绍了Scala中类的使用,通过类的构造,借助于new关键词创建不同的实例化对象,进而实现代码的可复用性。在本期我们将继续介绍跟类相关的另外两个主题,即构造器和单例对象


构造器

通过上一期Scala类的介绍,我们会发现一个非常显著的特征,即给类实例化过程中,所传递的参数都是相同类型或相同个数。那么问题来了,有没有这样一种类,允许用户创建不同类型(即包含不同参数列表或参数类型)的实例化对象?答案是肯定有的。这种类就是我们接下来要介绍的构造器,构造器的另一个用途是可以方便地设定类的初始属性值。


首先,我们来看一下,Scala中构造器的语法结构:

// 构造器的语法
class ClassName[(Parameters List)] // 主构造器

  def this[(Parameters List)] { 第一个辅助构造器
    this[(Parameters List)] // 调用主构造器
      ... // 辅助构造器的其他属性和方法
  }

  def this[(Parameters List)] {  第二个辅助构造器
    this[(Parameters List)] // 调用主构造器或辅助构造器
      ... // 辅助构造器的其他属性和方法
  }
}

针对如上的构造器语法,有几点内容需要说明:

  • 构造器可分为主构造器和辅助构造器;

  • 主构造器中除了方法之外的所有代码都会被执行;

  • 辅助构造器的创建一定是以this关键词开头;

  • 辅助构造器是没有返回值的;

接下来通过两个具体的例子,解释Scala中构造器的使用。如下代码只构造了含义参数列表的主构造器。其中参数使用了三种修饰方法,即val、var和非val非var

// 创建一个主构造器
class Friend(val name: String, var age: Int, education: String) {
  println("这就是一个最简单的主构造器")
}

// 创建一个对象,指定代码执行的主入口
object ConsDemo1 {
  def main(args: Array[String]): Unit = {
    // 创建类的实例对象
    val friend1 = new Friend("张三",28,"硕士")

    // val修饰的name变量可以访问,具有getter权限
    println("朋友的名字为:" + friend1.name) 
    // friend1.name = "李四"  将会报错,因为val修饰的变量具有不可变性,不可以设置新值,无setter权限

    // var修饰的age变量可以访问,具有getter权限
    println("他的年龄为:" + friend1.age) 
    friend1.age += 1
    // var修饰的age变量具有可变性,可以设置新值,有setter权限
    println("他第二年的年龄为:" + friend1.age) 

    // println(friend1.education)  将会报错,当变量没有val或者var修饰是,该变量既不可以访问也不可以设置新值
    // 如果使education字段具有getter权限和setter权限,可以在类内部将该变量重新赋值给新变量
    println(friend1)
  }
}

结果输出

通过如上代码可至,三种修饰方式的参数,各有不同的功能。val参数仅有getter权限,即理解为读权限;var参数包含getter权限和setter权限,即理解为可读可写权限;非val非var参数是没有读写权限的

在下面例子中,我们给类创建了主构造器和辅助构造器,其中辅助构造器的功能是计算税后收入。从代码的最后一部分可以看出,我们创建的两个实例化对象p2和p3时,给类Friend2传递了不同个数的参数。p2实际上调用的是类的主构造器,p3则调用的是类的辅助构造器。

// 创建包含主构造器和辅助构造器的类
class Friend2(val name: String, var age: Int, education: String) {
  var income: Int = _  // 变量初始化

  // 通过重新赋值,用户可以对Education变量进行访问和设置
  var Education = education 

  println("这就是一个最简单的主构造器")

  // 创建辅助构造器
  def this(name: String, age: Int, education: String,income:Int){
    this(name,age,education)  // 调用主构造器
    this.income = income // 参数赋值

    var res=0.0
    if (income <= 5000) {res = income - 0}
    else if (income <= 17000) {res = (income - (210 + (income-8000)*0.1))}
    else  {res = (income - (210 + 900 + (income-17000)*0.2))}

    println(s"${name}的收入为${income},经过计算,他的税后收入为${res}")
  }
}

// 创建一个对象,指定代码执行的主入口
object ConsDemo2 {
  def main(args: Array[String]): Unit = {
    // 对Friend2类实例化
    val p2 = new Friend2("张三",28,"硕士")
    // 修改属性的值
    p2.Education = "本科"  // 修改学历
    println(f"${p2.name}的年龄为${p2.age},他的学历为${p2.Education}")
    // 对Friend2类实例化
    val p3 = new Friend2("张三",28,"硕士"16500)
  }
}

结果输出

Scala中的构造器与对象【文末加群学习哦】

单例对象

Scala中是没有静态属性和静态方法的(即没有类似于Java中的voild修饰符),如果需要构造静态属性或静态方法,可以使用object关键词实现该功能,即在Scala中创建单例对象。在作者看来,Scala中单例对象的最大好处是实例化对象时可以不用new关键词。

单例对象可以分为孤立对象和伴生对象两种,孤立对象是指在一个Scala脚本文件中,对象的名称与类的名称不一致,这样的对象是不能访问类中的私有属性或方法的;伴生对象则是指脚本文件中,对象的名称与类的名称完全一致,此时对象和类之间是可以互相访问对方的私有属性和方法的。

接下来,我们通过一个简单的例子加以说明,代码如下:

// 创建一个与对象Person同名的半生类
class Person(name:String){
    println(s"${name}的编号为${Person.newId}.")
    // Person.newId就是直接调用了伴生对象中的newId方法
}



// 创建一个与类Person同名的伴生对象
  object Person{
//  定义一个私有变量
    private var lastid = 0
//  定义一个私有方法
    private def newId: Int ={
      lastid += 1
      lastid
    }
  }

// 创建一个对象,指定代码执行的主入口
object ObjectDemo {
  def main(args: Array[String]): Unit = {
    // 类的实例化
    val person1 = new Person("张三")
    val person2 = new Person("李四")
  }
}

结果输出


结语