前言
在《大数据之脚踏实地学19--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中是没有静态属性和静态方法的(即没有类似于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("李四") }}
结果输出
结语
本期的内容就介绍到这里,下一期我们将介绍Scala中类的继承。如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。同时,也欢迎各位朋友继续转发与分享文中的内容,让更多的人学习和进步。
(如果二维码过期了,可加微信lsx19890717,拉群哦)