scala 类和对象(二)- 4

实践操作定义Rational类

Rational类的定义规范

有理数rational定义:一个有理数rational可以表示为分数形式 n/d,其中n是分子(numerator),d是分母(denominator)

定义Rational

class Rational(n:Int, d:Int)

  • scala类的定义可以有参数,scala编译器会将不属于类成员和类方法的其它代码用作类的主构造函数
  • 创建Rational对象时,自动执行类定义的代码

scala> class Rational (n:Int, d:Int){
| println(“Created” + n + “/” + d)
| }
defined class Rational

scala> new Rational(1,2)
Created1/2
res14: Rational = Rational@5b7ee56c

重新定义类的toString方法

上面定义最后打印出Rational@5b7ee56c,是因为使用了default的类的toString()定义。default的实现是打印出对象的类名称+@+16进制数(对象的地址)
scala中可以使用override来重载基类定义的方法,必须使用override关键字表示重新定义的基类中的成员。比如:
scala> class Rational (n:Int,d:Int){
| override def toString = n+"/"+ d
| }
defined class Rational

scala> new Rational(1,3)
res15: Rational = 1/3

前提条件检查

给Rational设置前提条件 d不等于0
Scala 中解决这个问题的一个方法是使用 require 方法(require 方法为 Predef 对象定义的一个方法,Scala 环境自动载入这个类的定义,因此无需使用 import 引入这个对象)

scala> class Rational (n:Int,d:Int){
| require(d!=0)
| override def toString = n+"/"+d
| }
defined class Rational

scala> new Rational (5,0)
java.lang.IllegalArgumentException: requirement failed

添加成员变量

实现两个Rational对象相加的操作,加法返回一个新的Rational对象

class Rational (n:Int, d:Int) {
   require(d!=0)
   val number =n
   val denom =d 
   override def toString = number + "/" +denom 
   def add(that:Rational)  =
     new Rational(
       number * that.denom + that.number* denom,
       denom * that.denom
     )
}

类参数的访问仅限于定义类的方法本身,对于that来说,无法使用that.d来访问类参数,因此需要把d应以为类的成员变量
number 和 denom 以及 add 都可以不定义类型,Scala 编译器能够根据上下文推算出它们的类型。

自身引用

一般来说,引用类成员函数无需使用this,但是引用对象本身,this 就无法忽略

构造辅助函数

def this(n:Int) = this(n,1)

  • scala定义辅助构造函数使用this(…)语法,所有的辅助构造函数的名称为this.()

私有成员变量和方法

class Rational (n:Int, d:Int) {
    require(d!=0)
    private val g =gcd (n.abs,d.abs) 
    val number =n/g 
    val denom =d/g 
    override def toString = number + "/" +denom
    def add(that:Rational)  = 
      new Rational( 
        number * that.denom + that.number* denom,
        denom * that.denom 
      ) 
    def this(n:Int) = this(n,1) 
    private def gcd(a:Int,b:Int):Int =
      if(b==0) a else gcd(b, a % b)
}

定义运算符

Scala 中对方法的名称也没有什么特别的限制,你可以使用符号作为类方法的名称,比如使用 +、- 和 * 等符号。因此我们可以重新定义 Rational 如下:

class Rational (n:Int, d:Int) {
   require(d!=0)
   private val g =gcd (n.abs,d.abs) 
   val numer =n/g 
   val denom =d/g 
   override def toString = numer + "/" +denom
   def +(that:Rational)  =
     new Rational( 
       numer * that.denom + that.numer* denom,
       denom * that.denom 
     ) 
   def * (that:Rational) =
     new Rational( numer * that.numer, denom * that.denom)
   def this(n:Int) = this(n,1) 
   private def gcd(a:Int,b:Int):Int =
     if(b==0) a else gcd(b, a % b)
}

scala 中的标识符

scala中可以使用两种形式的标识符,字符数字和符号。字符数字使用字母或是下划线开头,后面可以接字母或是数字,符号$在scala中也看做字母。然而以 $开头的标识符为保留的scala编译器产生的标识符所使用,程序应该避免使用以 $使用的标识符

符号标志符包含一个或多个符号,如 + 、 : 和 ? 。对于 +、++、:::、<、 ?>、 :-> 之类的符号,Scala 内部实现时会使用转义的标志符。例如对 :-> 使用 coloncolonminus$greater 来表示这个符号。因此,如果你需要在 Java 代码中访问 :-> 方法,你需要使用 Scala 的内部名称 $colonminusminusgreater 。

混合标志符由字符数字标志符后面跟着一个或多个符号组成,比如 unary_+ 为 Scala 对 + 方法的内部实现时的名称。

字面量标志符为使用 " 定义的字符串,比如 “x”、“yield”。 你可以在 " 之间使用任何有效的 Scala 标志符,Scala 将它们解释为一个 Scala 标志符,一个典型的使用是 Thread 的 yield 方法, 在 Scala 中你不能使用 Thread.yield() 是因为 yield 为 Scala 中的关键字, 你必须使用 Thread.“yield”()来使用这个方法。

方法重载

和 Java 一样,Scala 也支持方法重载,重载的方法参数类型不同却使用同样的方法名称,比如对于 Rational 对象, + 的对象可以为另外一个 Rational 对象,也可以为一个 Int 对象,此时你可以重载 + 方法以支持和 Int 相加。

def + (i:Int) =
new Rational (numer + i * denom, denom)

隐式类型转换

上面我们定义 Rational 的加法,并重载 + 以支持整数, r + 2 ,但如果我们需要 2 + r 如何呢?

x + 3 没有问题,3 + x 就报错了,这是因为整数类型不支持和 Rational 相加。

如果 Int 类型能够根据需要自动转换为 Rational 类型,那么 3 + x 就可以相加。Scala 通过 implicit def 定义一个隐含类型转换,比如定义由整数到 Rational 类型的转换如下:

implict def intToRational(x:Int) = new Rational(x)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值