9-Scala的继承关系

前言

本节将介绍Scala中的继承关系,包括Any、AnyVal、AnyRef。
环境:
Windows + Scala-2.12.8

1. Scala 的类继承关系

在这里插入图片描述
在Any 类的源代码中有如下方法:

package scala
abstract class Any {
  def equals(that: Any): Boolean
  def hashCode(): Int
  def toString(): String
  final def getClass(): Class[_] = sys.error("getClass")
  final def ==(that: Any): Boolean = this equals that
  final def != (that: Any): Boolean = !(this == that)
  final def ##(): Int = sys.error("##")
  final def isInstanceOf[T0]: Boolean = sys.error("isInstanceOf")
  final def asInstanceOf[T0]: T0 = sys.error("asInstanceOf")
}

Scala 提供了九个内建的值类:Byte、Short、Char、Int、Long、Float、Double、Boolean和Unit。
如果你进行这样的尝试是错误的:
在这里插入图片描述
在Int 类型的源代码中没有如下的方法,但是却可以使用:
在这里插入图片描述
因为,max、abs都定义在scala.runtime.RichInt类中,并且存在从Int 类到 RichInt 的隐式转换。所以,Int 类型的对象能够使用这些方法。

2. 基本类型的实现机制

在Scala 中类型为Int 的整数在必要时都会透明地被转换成类型为java.lang.Integer 的“装箱整数”。
不过,Scala中的装箱跟Java 比要透明的多。

比如,在Java 中:

public class Test {
	public static void main(String[] args) {
		System.out.println(isEqual(13, 13));
		System.out.println(isEqual2(13, 13));
	}
	static boolean isEqual(int x, int y) {
		return x == y;
	}
	static boolean isEqual2(Integer x, Integer y) {
		return x == y;
	}
}
true
true

但是,由于Java 的整形缓存机制(-128~127)会缓存和重用,也就是说isEqual2(13, 13) 的结果应该是false,由于缓存机制所以是true,比如换成大于127的数:(仅仅是博主在测试中遇到的一个问题
在这里插入图片描述
在Scala 中:
在这里插入图片描述
在Scala中,== 和 eq 的对比如下:
在这里插入图片描述

3. 底型类

在Scala 中,最底部为scala.Null 和 scala.Nothing。它们是Scala面向对象的类型系统用于统一处理某些”极端情况”的特殊类型。
Null 并不兼容与值类型(上面的类继承图也可以看出来),如:
在这里插入图片描述
Nothing的用途之一是给出非正常终止的信号。
如Predef 标准库中有一个error 方法,定义如下:

def error(message: String): Nothing = 
  throw new RuntimeException(message)

error 的返回类型是Nothing,这告诉使用方 该方法并不会正常返回(它会抛出异常)。由于Nothing 是每个其他类型的子类型,可以非常灵活的使用error 这样的方法,如:
注:这是书上的例子(但是经博主查看源码,已经没有了error 方法,所以不能运行,猜测可能是版本问题)

def divide(x: Int, y: Int): Int = {
  if (y != 0) x / y
  else error("can't divide by zero")
}

虽然不能运行,还是解析一下。因为error 的返回类型为Nothing,而divide 的返回类型是Int。如果,Nothing 不是Int 的子类型,编译时不能通过的。但是,Nothing 是Int 的子类型,所以编译是能够通过的(error存在的前提下)。

4. 定义自己的值类型

只有特定的几个类可以成为值类型。它必须有且仅有一个参数,并且在内部除了def 之外不能有其他任何东西。不经如此,也不能有其他类扩展自值类,如:

class Dollars(val amount: Int) extends AnyVal {
  override def toString() = "$" + amount
}

(amount 为参数化字段)是不是觉得有点像Scala 内建的值类型:
在这里插入图片描述
另外,还因避免类型单一化。要想尽可能发挥Scala 类继承关系的好处,应该试着对每个领域定义一个新类。比如,想要生成一段HTML 代码,你可能会这样做:

def title(text: String, anchor: String, style: String): String = 
  s"<a id='$anchor'><h1 class='$style'>$text</h1></a>"

你传参顺序错误的情况下,编译器不能帮你检测出来,造成了如下结果:
在这里插入图片描述
所以我们需要对每一个领域定义一个细微类型(既没有方法,也没有字段),如:

class Anchor(val value: String) extends AnyVal
class Style(val value: String) extends AnyVal
class Text(val value: String) extends AnyVal
class Html(val value: String) extends AnyVal

然后,可以定义一个更丰满的title方法:

def title(text: Text, anchor: Anchor, style: Style): Html = {
  new Html(
    s"<a id='${anchor.value}'>" +
      s"<h1 class='${style.value}'>" +
      text.value +
      "</h1></a>"
  )
}

现在,如果传参类型不正确,编译器会报错,如:
在这里插入图片描述
只有正确的传参才可以:
在这里插入图片描述

后续篇章

10-特质-Scala

完!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值