探索Scala(5)-- 基本类型

文本讨论一下Scala语言基本类型的实现方式

Java基本类型

Java的数据类型大致可以分为两类:基本(Primitive)类型和对象类型。基本类型一共有8种,分别是boolean、byte、short、char、int、long、float、double。为了把基本类型融入OO系统,Java提供了包装类(Wrapper)。包装类在包java.lang里,一共8个,分别与基本类型一一对应,它们是:Boolean、Byte、Short、Character、Integer、Long、Float和Double。Java5引入的自动装箱拆箱(Autoboxing
and Unboxing
)语法让基本类型和OO系统结合的更自然,但仍然不够完美。

Scala基本类型

Scala在Java的基础上迈出了一大步,从语法层面彻底消灭了Primitive类型。也就是说,一切皆是对象,如下面代码所示:

val x = 1
println(x.toString)

3.to(8).foreach {
    i => println(i)
}

和Java的8种基本类型相对应,Scala也定义了8种基本类型,它们是:Boolean、Byte、Short、Char、Int、Long、Float和Double。这8种基本类型都定义在scala包里。有趣的是,这8种基本类型虽然有相应的类定义,但是和其他类还是有区别的:这些类的实例并不是对象,而是直接映射为相应的primitive类型。比如,下面是Int类的部分代码:

package scala

/** `Int`, a 32-bit signed integer (equivalent to Java's `int` primitive type) is a
 * subtype of [[scala.AnyVal]]. Instances of `Int` are not
 * represented by an object in the underlying runtime system.
 *
 * There is an implicit conversion from [[scala.Int]] => [[scala.runtime.RichInt]]
 * which provides useful non-primitive operations.
 */
final abstract class Int private extends AnyVal {
    ...
}

底层使用Primitive类型

虽然从语法上来看,基本类型和对象类型已经没有任何区别。但是在底层,Scala使用的仍然是primitive类型。比如下面这个方法:

def collect(x: Int, y: Int): Array[Int] = {
    Array(x, y + 1)
}

经过Scala编译之后再反编译,可以得到下面的Java代码:

public int[] collect(int x, int y) {
    return new int[] {x, y + 1};
}

包装为Java包装类型

必要时,Scala会把基本类型包装成相应的Java包装类型,比如下面这个方法:

def boxToXXX() = {
    val x = 1
    val str = x.toString()
    val hc = x.hashCode()
}

反编译得到下面的Java代码:

int x = 1;
Integer boxedX = scala.runtime.BoxesRuntime.boxToInteger(x);
boxedX.toString();
boxedX.hashCode();

BoxesRuntime类的boxToInteger()方法调用了Integer的valueOf()方法,如下所示:

public static java.lang.Integer boxToInteger(int i) {
    return java.lang.Integer.valueOf(i);
}

隐式转换为Java包装类型

基本类型也可以通过隐式转换变为Java包装类型,比如下面这个方法:

def implicitConversion() = {
    val x = 1
    val y = 2
    x.compareTo(y)
}

反编译之后,得到下面的Java代码:

int x = 1;
int y = 2;
Integer boxedX = scala.Predef$.MODULE$.int2Integer(x);
Integer boxedY = scala.Predef$.MODULE$.int2Integer(y);
boxedX.compareTo(boxedY);

隐式转换方法定义在Predef里,下面是Predef的相应代码:

object Predef {
    implicit def int2Integer(x: Int) = java.lang.Integer.valueOf(x)
}

隐式转换为RichXXX

为了给基本类型添加更多的方法,Scala给每个基本类型都定义了一个新的包装类,这些包装类在scala.runtime包里,分别是:RichBoolean、RichByte、RichShort、RichChar、RichInt、RichLong、RichFloat和RichDouble。比如下面这个方法:

def richXXX() = {
    val x = -1
    x.abs
}

反编译之后,得到下面的Java代码:

int x = -1;
RichInt richX = scala.Predef$.MODULE$.intWrapper(x);
richX.abs();

下面是Predef的相应代码:

object Predef extends LowPriorityImplicits {...}
private[scala] abstract class LowPriorityImplicits {
    @inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)
}

隐式转换为BigXXX

为了支持任意精度的整数和小数,Java提供了BigIntegerBigDecimal类,这两个类在java.math包里。Scala在scala.math包里提供了两个类似的类:BigIntBigDecimal。这两个类都重载了各种运算符,所以使用起来更加自然:

def bigXXX() = {
    val x: BigInt = 237
    val y = (x * 7) pow 95
}

下面是反编译之后的bigXXX方法:

int x = 237;
BigInt bigX = BigInt$.MODULE$.int2bigInt(x);
BigInt y = bigX.$times(7).pow(95);

下面是BigInt相应代码:

object BigInt {
    implicit def int2bigInt(i: Int): BigInt = apply(i)
}
final class BigInt(val bigInteger: BigInteger) {
    def + (that: BigInt): BigInt = new BigInt(this.bigInteger.add(that.bigInteger))
    def - (that: BigInt): BigInt = new BigInt(this.bigInteger.subtract(that.bigInteger))
    def * (that: BigInt): BigInt = new BigInt(this.bigInteger.multiply(that.bigInteger))
    def / (that: BigInt): BigInt = new BigInt(this.bigInteger.divide(that.bigInteger))
    def pow (exp: Int): BigInt = new BigInt(this.bigInteger.pow(exp))
}

可见BigInt只是简单的包装Java的BigInteger而已,而且还提供了一个单例对象。为了提高效率,BigInt还采用了和java.lang,Integer类似的缓存优化,把-1024到1024之间的数缓存了起来:

object BigInt {
    private val minCached = -1024
    private val maxCached = 1024
    private val cache = new Array[BigInt](maxCached - minCached + 1)

    def apply(i: Int): BigInt =
        if (minCached <= i && i <= maxCached) {
            val offset = i - minCached
            var n = cache(offset)
            if (n eq null) { n = new BigInt(BigInteger.valueOf(i.toLong)); cache(offset) = n }
            n
        } else new BigInt(BigInteger.valueOf(i.toLong))
}

参考资料

Scala API

Scala源代码

《Programming in Scala》第二版

《Scala for the Impatient》

时间: 2024-08-29 17:55:38

探索Scala(5)-- 基本类型的相关文章

Scala 深入浅出实战经典 第53讲:Scala中结构类型实战详解

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/pR_4sY0cJLs/优酷:http://v.youku.com/v_show/id_

Scala 深入浅出实战经典 第54讲:Scala中复合类型实战详解

王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 腾讯微云:http://url.cn/TnGbdC 360云盘:http://yunpan.cn/cQ4c2UALDjSKy 访问密码 45e2土豆:http://www.tudou.com/programs/view/a6qIB7SqOlc/优酷:http://v.youku.com/v_show/id_

探索Scala(8)-- 关键字

本文比较一下Java和Scala语言的关键字 Java关键字 Java一共有50个关键字(keywords),其中有2个是保留字,目前还不曾用到:goto和const.true.false和null看起来很像关键字,但实际上只是字面量而已.本文粗略的把true.false和null也看做Java关键字,认为Java一共有53个关键字.下面是大致归类的Java关键字列表: assert boolean, byte, short, char, int, long, float, double, vo

Scala学习 - 基础类型

Scala中的类型相对于Java来说,与.net的想法更为接近,所有的类型都是基于一个基础类型,包括值类型也是继承自该类型: Java中值类型是语言直接提供的,这点上有点不同: 类型关系图如下: 其中所有类型的基类与Any Any之后分为两个AnyVal与AnyRef 其中AnyVal是所有值类型的父类型 AnyRef是所有引用类型的父类型 与其他语言稍微有点不同的是,Scala还定义了底类型 其中Null类型是所有引用类型的底类型,及所有AnyRef的类型的空值都是Null 而Nothing是

scala 数组 基本类型

变量尽量用valvar 是不可变 final 常用的 Int? Double? Long? String没有基本类型.scala 任何对象都继承Any Int Double 继承AnyVal String继承java.lang.String.scal数组java aa[]1.写法scala val a=new Array[String](3)2.用法访问数据用下标a(0) ="abc"3.调用scal调用() 其实是在调用数组的apply()方法 所有a(0) 就是a.apply(0)

scala一些高级类型

package com.ming.test import scala.collection.mutable.ArrayBuffer import scala.io.Source import java.awt.image.BufferedImage import javax.imageio.ImageIO import java.io.File /** * 高级类型 */ //单例类型,链式调用 class Document{ def setTitle(title:String)={this}

scala如何解决类型强转问题

scala属于强类型语言,在指定变量类型时必须确定数据类型,即便scala拥有引以为傲的隐式推到,这某些场合也有些有心无力. 例如:java同属强类型语言,但java可以进行类型强转.因此在进行面向接口编程时,借助类型强转,只要编码没有问题,就可以使用准备使用的class类.但在scala中,这条路就走不通了.因为scala没有类型强壮. 那如何办呢? 众所周知,scala编译后变成字节码文件,运行在jvm中.那么从骨子里,scala可以说是脱胎于java,同样scala可以调用java所有的类

[Scala基础系列 10]Scala泛型、类型边界

1.泛型和类型边界 1.1.上限(upper bounds) 我们先看一个简单的实例,用于判断两个变量中较大的值,其中两个变量的类型均为Int型 package com.tv189.advanced /** * Created by molyeo on 2015/8/12. */ class PairInt(val first: Int, val second: Int) { def bigger = { if (first.compareTo(second) > 0) first else s

探索Scala(3)-- 单例对象

研究一下Scala语言的单例对象(Singleton Objects),为下一篇文章做准备. static不是关键字 上一篇文章提到过,interface并不是Scala语言关键字,可以自由使用.同样,static在Scala里也没有特殊的含义,也是可以自由使用的,如下面代码所示: 单例对象 Java并不是完美的面向对象语言,包括很多缺陷,比如允许static字段和方法,primitive类型,等等.Scala语言在这些方面都有所改进,所以号称是比Java更OO的语言.既然去掉了static关键