Scala_类-》Scala 类的构造

 

本篇文章主要科普如何创建一个Scala的类,主要从以下几个方面阐述:

 

1. 基础的Scala构造函数

  1.1 基础语法

  1.2 构造参数对访问权限的影响

  1.3 对构造函数增加限定符

2.Scala类的辅助构造函数

  2.1 辅助构造函数 基本语法

  2.2 辅助构造函数 注意的事项

3.辅助构造函数对主构造函数的调用

4.继承关系下,调用父类构造函数

  4.1 一个基本的继承示例

  4.2 如何调用父类的构造函数

  4.3 构造函数经验总结

5.模板类 case 方法

  5.1 模板类样例

  5.2 使用模板类的构造方法

6.不调用new 方法创建类的实例   伴生类,  apply 方法

  6.1 伴生类与apply方法

  6.2 伴生类 apply 方法的重载

  6.3 伴生类 的 继承 与 apply 方法

 

简介:Scala 的类创建与Java 有较大不同,比如:

1)Scala 中创建类,可以不使用new 关键字。

2)Scala 中 可以通过模板类生成一些基础的方法。

。。。

 

下面根据目录对以上的点进行总结归纳:

 

1. 基础的Scala构造函数

 

1.1 基础语法

scala 的基础构造函数是直接写在类定义上的。

参考下面案例:

package classDefined

import scala.collection.mutable.ArrayBuffer

/**
  * Created by szh on 2018/12/4.
  */
class ClassOrigin(var name: String, var age: Int, var tel: Option[Long] = None, var address: Option[String] = None) {

  override def toString: String = {
   val d = new StringBuffer()
    d.append(name.toString).append(" ")
    d.append(age.toString).append(" ")
    d.append(tel.toString).append(" ")
    d.append(address.toString)
    d.toString
  }
}

object TestClassDefine1 extends App {

  val userA = new ClassOrigin(name = "sunzhenhua", age = 22)
  println(userA)

}

 

1.2 构造参数对访问权限的影响

此外,我们看下用不同修饰符,修饰构造函数参数的效果

不同修饰符的可见性
可见性可访问可修改
var
val

缺省可见性

(非 var , 非 val)

给val 和 var

加 private 关键字

 

参考案例 :

package classDefined

/**
  * Created by szh on 2018/12/4.
  */
class ClassOrigin2(name: String, val age: Int, private var tel: Option[Long] = None, address: Option[String] = None) {

  override def toString: String = {
    val d = new StringBuffer()
    d.append(name.toString).append(" ")
    d.append(age.toString).append(" ")
    d.append(tel.toString).append(" ")
    d.append(address.toString)
    d.toString
  }
}

object TestClassDefine2 extends App {

  val userA = new ClassOrigin2(name = "sunzhenhua", age = 22)
  println(userA)

  //缺省访问权限
  println(userA.name)

  //val访问权限
  userA.age = 33

  //给var/val 增加private 限定符
  println(userA.tel)

}

 

1.3 对构造函数增加限定符

注意Scala 的构造函数,还可以用不同修饰符进行修饰,比如 private  

加了 private 修饰符,类的构造函数就是私有的,不能通过 new 创建。

示例 :

package classDefined

/**
  * Created by szh on 2018/12/4.
  */
class ClassOrigin3 private (name: String, val age: Int, private var tel: Option[Long] = None, address: Option[String] = None) {

  override def toString: String = {
    val d = new StringBuffer()
    d.append(name.toString).append(" ")
    d.append(age.toString).append(" ")
    d.append(tel.toString).append(" ")
    d.append(address.toString)
    d.toString
  }
}

object TestClassDefine3 extends App {

  //val userA = new ClassOrigin3(name = "sunzhenhua", age = 22)
  //println(userA)

}

 

但是,这样仅有一个构造函数的类显然不能满足 所有的需求。为此,需要辅助构造函数进行支持。

 

 

2.Scala类的辅助构造函数

 

2.1 辅助构造函数 基本语法

辅助构造 主要是对单一的构造函数的一个辅助支持。 但是这个功能, 个人感觉跟Scala 的参数的默认值有些重复,

示例:

package classDefined

/**
  * Created by szh on 2018/12/4.
  */
class ClassConstructSupport(var name: String, var age: Int, var tel: Option[Long] = None, var address: Option[String] = None) {

  def this(name: String, age: Int) {
    this(name, age, None, None)
  }

  def this(name: String) {
    this(name, 0, None, None)
  }

  override def toString: String = {
    val d = new StringBuffer()
    d.append(name.toString).append(" ")
    d.append(age.toString).append(" ")
    d.append(tel.toString).append(" ")
    d.append(address.toString)
    d.toString
  }
}

object TestClassDefine4 extends App {

  val userA = new ClassConstructSupport(name = "sunzhenhua", age = 22)
  println(userA)

  val userB = new ClassConstructSupport("copy")
  println(userB)

}

此外,辅助构造函数有些需要主要的地方

 

2.2 辅助构造函数 注意的事项

 

1.辅助构造函数不能设置修饰符

错误示例:

def this(val name: String, age: Int) {

2.辅助构造函数的第一行代码,必须从调用之前的构造函数开始

错误示例:

 def this(name: String, age: Int) {
    var age2 = 33
    this(name, age2, None, None)
  }

3.辅助构造函数必须用 this 命名创建

4.每个构造函数必须有不同的签名

5.一个构造函数通过 this 调用另一个不同的构造函数。

 

 

3.辅助构造函数对主构造函数的调用

 

辅助构造函数对主构造函数主要通过  this 进行调用。

 

 

4.继承关系下,调用父类构造函数

 

4.1 一个基本的继承示例

 

本篇不详细介绍 scala 继承,但是给出一个 基本的模板:

package classDefined

/**
  * Created by szh on 2018/12/4.
  */
class ClassConstructSupportExtend(var name: String, val age: Int, var tel: Option[Long] = None, var address: Option[String] = None) {

  def this(name: String) {
    this(name, 0, None, None)
  }

  def this() {
    this("")
  }

  override def toString: String = {
    val d = new StringBuffer()
    d.append(name.toString).append(" ")
    d.append(age.toString).append(" ")
    d.append(tel.toString).append(" ")
    d.append(address.toString)
    d.toString
  }
}

class ClassConstructSupportExtendChild(name: String, var qq: Long = 0) extends ClassConstructSupportExtend(name) {

  override val age: Int = 22
}

object TestClassDefine7 extends App {

  val userA = new ClassConstructSupportExtendChild(name = "sunzhenhua")
  println(userA)

}

 

 

 

4.2 如何调用父类的构造函数

 

       可以在子类的主构造函数中控制被调用的超类的构造函数,

但是无法控制被子类构造调用的超类构造函数。

 

原因:

   对子类构造函数而言,因为一个辅助构造函数的第一行必须去调用当前类的另一个构造函数,

那么它就无法调用超类的构造函数。

 

额外注意的点:

1.继承的主构造函数,继承的同名参数,不能修改其类型

2.尽量不要使用参数默认值混用的方式,即若有辅助构造函数,尽量不要使用参数默认值,容易产生编译错误 !!!!

 

下面给出一个示例:

package classDefined

/**
  * Created by szh on 2018/12/4.
  */
class ClassConstructSupportExtend(var name: String, val age: Int, var tel: Option[Long] = None, var address: Option[String] = None) {

  def this(name: String) {
    this(name, 0, None, None)
  }

  def this() {
    this("")
  }

  override def toString: String = {
    val d = new StringBuffer()
    d.append(name.toString).append(" ")
    d.append(age.toString).append(" ")
    d.append(tel.toString).append(" ")
    d.append(address.toString).append(" ")
    d.toString
  }
}

class ClassConstructSupportExtendChild(name: String, var qq: Long, var mail: String) extends ClassConstructSupportExtend(name) {

  override val age: Int = 22

  def this(name: String, mail: String) {
    this(name, 0, mail)
  }

  def this(mail: String) {
    this("???", mail)
  }

  override def toString: String = {
    val tmp = new StringBuffer(super.toString)
    tmp.append(qq).append(" ")
    tmp.append(mail).append(" ")
    tmp.toString
  }
}

object TestClassDefine7 extends App {

  val userA = new ClassConstructSupportExtendChild(name = "sunzhenhua", mail = "KK")
  println(userA)

  var userB = new ClassConstructSupportExtendChild("870991173@qq.com")
  println(userB)

}

 

 

4.3 构造函数经验总结

 

1.主构造函数,参数尽量写全部的参数。在辅助构造函数对参数进行精简。

 

2.若存在继承并调用主类构造函数的场景。由于只能继承一个主类的构造函数,所以,推荐继承参数最多的构造函数。

 

 

 

5.模板类 case 方法

 

 5.1 模板类样例

 

将一个类定义为case类会生成许多模板代码,好处在于:

1.会生成一个apply 方法,这样可以不调用new 关键字创建新的实例。

2.由于case类的构造函数参数默认是 val, 那么构造函数参数会自动生成访问方法。如果是 var 也会有修改方法。

3.会生成一个默认的toString 方法。

4.会生成一个 unapply 方法,在模式匹配时很好用。

5.会生成equals 和 hashCode 方法。

6.还有一个copy 方法。

 

下面给出一个模板类的样例:

case class Person(var name: String, var age: Int)

是不是非常简易 !!

 

5.2 使用模板类的构造方法

 

当使用 case 生成模板类,由于生成的是apply 方法,此时我们不需要使用 new 关键字,就可以生成一个实例了。

package classDefined


case class Person(var name: String, var age: Int)

/**
  * Created by szh on 2018/12/5.
  */
object ClassCaseConstruct extends App {

  val d = Person("cc", 22)
  println(d.toString)
}

 

 

 

6.不调用new 方法创建类的实例   伴生类,  apply 方法

 

  6.1 伴生类与apply方法

 

伴生类,其实主要是 类 + 同名的对象 实现的。使用 伴生类 的 apply 的方法,可以在生成类实例的时候,不需要 new 关键字。

下面是一个简易的伴生类。

 

  6.2 伴生类 apply 方法的重载

伴生类的apply 的方法,也可以进行重载。下面演示一个较为复杂的案例。

跟 6.1 结合成一个样例:

package classDefined

class PersonCC {

  var userName = ""
  var password = ""
  var age = 0

  override def toString : String = {
    val s = new StringBuffer()
    s.append(userName).append(" ")
    s.append(password).append(" ")
    s.append(age).append(" ")
    s.toString
  }
}

object PersonCC {

  def apply(userName: String = "sunzhenhua", password: String = "123456", age: Int): PersonCC = {
    val d = new PersonCC
    d.userName = userName
    d.password = password
    d.age = age
    d
  }

  def apply(userName : String): PersonCC = {
    this.apply(userName = userName, age = 0)
  }

}


/**
  * Created by szh on 2018/12/5.
  *
  * @author sunzhenhua
  */
object OjectClassConstruct extends App {

  val d = PersonCC(age = 12)
  println(d.toString)

  val f = PersonCC("cccc")
  println(f.toString)

}

 

 

  6.3 伴生类 的 继承 与 apply 方法

当我们继承上面的 PersonCC ,apply 方法是否帮我们生成了一个真正的构造函数呢?

 

 

可以看到实际上,apply 并未为我们生成真实的构造函数。 只是。我们在对象中定义一个 apply 方法,可以减少 new 生成对象而已。apply 实际上,还是调用了对象真正的构造函数生成实例。这点我们要特别注意。

示例代码:

package classDefined

class PersonCC {

  var userName = ""
  var password = ""
  var age = 0

  override def toString: String = {
    val s = new StringBuffer()
    s.append(userName).append(" ")
    s.append(password).append(" ")
    s.append(age).append(" ")
    s.toString
  }
}

object PersonCC {

  def apply(userName: String = "sunzhenhua", password: String = "123456", age: Int): PersonCC = {
    val d = new PersonCC
    d.userName = userName
    d.password = password
    d.age = age
    d
  }

  def apply(userName: String): PersonCC = {
    this.apply(userName = userName, age = 0)
  }

}

//class PersonDD(userName: String, password: String, age: Int) extends PersonCC(userName, password, age) {
//
//
//}

class PersonDD2(userName: String, password: String, age: Int) extends PersonCC {


}


/**
  * Created by szh on 2018/12/5.
  *
  * @author sunzhenhua
  */
object OjectClassConstruct extends App {

  val d = PersonCC(age = 12)
  println(d.toString)

  val f = PersonCC("cccc")
  println(f.toString)

  val g = new PersonDD2("22","cc",10)
  println(g.toString)

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值