Scala 覆写抽象字段和具体字段

Scala 覆写抽象字段和具体字段

Scala程序设计 第2版 - 原版.pdf 下载:https://download.csdn.net/download/u014646662/10805074

1 覆写trait中的字段

2 覆写类字段

3 覆写抽象类型

对人工智能感兴趣的同学,可以点击以下链接:

现在人工智能非常火爆,很多朋友都想学,但是一般的教程都是为博硕生准备的,太难看懂了。最近发现了一个非常适合小白入门的教程,不仅通俗易懂而且还很风趣幽默。所以忍不住分享一下给大家。点这里可以跳转到教程。

https://www.cbedai.net/u014646662

1 覆写trait中的字段

下面列举了一段精心设计的示例代码。在字段初始化之前,该示例会调用这个尚未定义的字段:

package cn.com.tengen.test.obj

trait TestTrait {
  val value: Int
  val inverse = 1.0/value
}

object Test {
  def main(args: Array[String]): Unit = {
    val o = new TestTrait {
      override val value: Int = 10
      println("TestTrait: value = "+value+", inverse = "+inverse)
    }
  }
}


//输出:
TestTrait: value = 10, inverse = Infinity

正如你所预计的那样,inverse 变量过早被计算了。尽管没有抛出除零异常(divide-byzeroexception),但是编译器仍认为inverse 值无穷大。Scala 为此类问题提供了两个解决方案。第一个方案是使用惰性值(lazy value)

package cn.com.tengen.test.obj

trait TestTrait {
  val value: Int
  lazy val inverse = 1.0/value
}

object Test {
  def main(args: Array[String]): Unit = {
    val o = new TestTrait {
      override val value: Int = 10
      println("TestTrait: value = "+value+", inverse = "+inverse)
    }
  }
}

//输出:
TestTrait: value = 10, inverse = 0.1

现在,inverse 成功地被初始化,并被赋予了合法值,只有在调用时lazy 关键字才能起到作用。这是因为lazy 会推迟对变量进行估值,直到有代码需要使用该值。假如某一val 变量是惰性值,请确保尽可能地推迟对该val 值的使用。

第二个方案:预先初始化字段

trait TestTrait {
  val value: Int
  val inverse = 1.0/value
  println("TestTrait: value = "+value+", inverse = "+inverse)
}

object Test {
  def main(args: Array[String]): Unit = {
    val o = new  {
      val value: Int = 10
    } with TestTrait
  }
}

//输出:
TestTrait: value = 10, inverse = 0.1

在with TestTrait 子句执行之前,我们便已实例化了一个匿名内部类并在代码块中初始化了该内部类的值字段。这确保了在执行TestTrait 特征体之前,value 字段已初始化完毕。

尽可能避免(在类中和trait 中)使用var 字段,而使用公共 var 字段则尤为危险。

不过,val 所提供的可见性保护并非无懈可击。我们可以在初始化子类实例时对trait 中的val 字段进行覆写,不过初始化完之后,该字段仍为不可变值。

2 覆写类字段

类中声明的成员,其表现与trait 中的成员大致相同。为了能够完整地描述如何覆写类字段,下面这个示例中的继承类既覆写了val 字段,又对var 字段进行了重新赋值:

package cn.com.tengen.test.obj

class Test {
  val name = "Test"
  var count = 0
}

class TestSon extends Test {
  override val name = "TestSon"
  count = 1
}


object Test {
  def main(args: Array[String]): Unit = {
    val s = new TestSon()
    println(s.name)
    println(s.count)
  }
}


//输出:
TestSon
1

覆写具体val 字段时,override 关键字是必不可少的,不过对于count 这个var 字段而言,则不然。这是因为修改val 字段意味着我们正在修改某一常量(val 字段)的初始化过程,这类“特殊”操作需要使用override 关键字。

正如我们所预计的那样,继承类对这两个字段都进行了覆写。下面对之前的示例进行修改,将基类中的val 字段和var 字段都修改成abstract 字段:

package cn.com.tengen.test.obj

abstract class Test {
  val name:String
  var count:Int
}

class TestSon extends Test {
  val name = "TestSon"
  var count = 1
}

object Test {
  def main(args: Array[String]): Unit = {
    val s = new TestSon()
    println(s.name)
    println(s.count)
  }
}

由于这些字段均声明为abstract 类型,因此TestSon中不再需要override 关键字。但是var 和 val不能少

有必要强调一下:name 和count 是抽象字段,它们并不是包含默认值的具体字段。如果在Java 类中进行类似的声明,如String name,Java 将会声明一个具有默认值的具体字段,而在本例中默认值为null。Java 并不支持抽象字段,只支持抽象方法。

3 覆写抽象类型

abstract class Test {
  type In
  val source: In
  def read: String // 该方法会读取数据源内容,并返回字符串
}
class TestSon(val source: String) extends Test {
  type In = String
  def read: String = source
}

该示例演示了如何声明抽象类型以及如何在继承类中为该抽象类型定义具体值。Test 类声明了In 类型,但却未初始化该类型。而具体继承类TestSon使用type In = String 语句为该类型提供了具体值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值