scala 类型 的最详细解释

scala 是一个强类型的语言,但是在编程时可以省略对象的类型.

java中对象类型(type)与类(class)信息

jdk1.5 前 类型与类是一一映射,类一致类型就一致.

1.5 后引入了泛型,jvm 选择运行时擦除类型, 类型不可以只通过类信息进行判断.
比如: List<String>,List<Integer> 的class 都是 Class<List>,然而他们的类型是不相同的,泛型是需要通过反射来进行获得,
同时java通过增加 Type 来表达这种类型.

List<String> 的类型由 类构造器 和 类型参数 组成. 和 List<Integer> 完全不相同.

scala中类型

scala 没有用java自己的类型接口,使用 scala.reflect.runtime.universe.Type 接口

  1. 类获得类型或类信息

// 获取类型信息
import scala.reflect.runtime.universe._

class A

typeOf[A]
res44: reflect.runtime.universe.Type = A

// 获取类信息
classOf[A]
res52: Class[A] = class A
  1. 对象获得类信息

另外java 中对象获取类信息可以通过 getClass方法,scala继承了这个方法.

val a = new A

a.getClass
res53: Class[_ <: A] = class A

scala 类型与类区别

scala> class A { class B }  // 嵌套类

scala> val a1 = new A
scala> val a2 = new A

scala> val b1 = new a1.B
scala> val b2 = new a2.B

scala> b1.getClass
res8: Class[_ <: a1.B] = class A$B

// 嵌套类的类信息是一致的是 A&B
scala> b1.getClass == b2.getClass
res7: Boolean = true

// 类型是不同的
scala> typeOf[a1.B] == typeOf[a2.B]
res10: Boolean = false

typeOf[a1.B]
res9: reflect.runtime.universe.Type = a1.B

类(class)与类型(type)是两个不一样的概念,类型(type)比类(class)更”具体”,任何数据都有类型。类是面向对象系统里对同一类数据的抽象,在没有泛型之前,类型系统不存在高阶概念,直接与类一一映射,而泛型出现之后,就不在一一映射了。比如定义class List[T] {}, 可以有List[Int] 和 List[String]等具体类型,它们的类是同一个List,但类型则根据不同的构造参数类型而不同。

类包括类型,类型一致他们的类信息也是一致的. 类型不一致,但是类可能一致,类型是所有编程语言都有的概念,一切数据都有类型。类更多存在于面向对象语言,非面向对象语言也有“结构体”等与之相似的概念;类是对数据的抽象,而类型则是对数据的”分类”,类型比类更“具体”,更“细”一些。

scala 内部依赖类型

class A{
     | class B;
     | def foo(b:B) = println(b)
     | }
defined class A

scala> val a1 = new A
a1: A = A@34692767

scala> val a2 = new A
a2: A = A@d9c54cd

scala> val b1 = new a1.B
b1: a1.B = A$B@156aba9a

scala> val b2 = new a2.B
b2: a2.B = A$B@3829edd5

在java 中 内部类创建的对象是相同的,但是scala中b1 和 b2 是不同的类型.

a1.foo(b2)
<console>:17: error: type mismatch;
 found   : a2.B
 required: a1.B
       a1.foo(b2)
              ^

a1.foo方法接受的参数类型为:a1.B,而传入的b2 类型是 a2.B,两者不匹配。

路径依赖类型;比如上面的 A.this.B 就是一个路径依赖类型,B 前面的路径 A.this 随着不同的实例而不同,比如 a1 和 a2 就是两个不同的路径,所以a1.B 与 a2.B也是不同的类型。
  1. 内部类定义在Object中: 路径 package.object.Inner
  2. 内部类定义在class/trait 里:
class A {
    class B
    val b = new B // 相当于 A.this.B
}   

类路径 A.B

class A  { class B }
class C extends A { val x = new super.B } // 相当于 C.super.B

类路径 C.super.B

怎么让 a1.foo 方法可以接收 b2 参数 ?
类型投影(type projection)

在scala里,内部类型(排除定义在object内部的),想要表达所有的外部类A实例路径下的B类型,即对 a1.B 和 a2.B及所有的 an.B类型找一个共同的父类型,这就是类型投影,用 A#B的形式表示。

def foo(b: A#B)

结构类型

结构类型(structural type)为静态语言增加了部分动态特性,使得参数类型不再拘泥于某个已命名的类型,只要参数中包含结构中声明的方法或值即可。

def free( res: {def close():Unit} )
{ 
        res.close 
}

free(new { def close()=println("closed") })
closed

也可以使用Type定义别名

type X = { def close():Unit }
defined type alias X
def free(res:X) = res.close
free(new { def close()=println("closed") })
closed

如果某一类实现了close方法也可以直接传入

object A { def close() {println("A closed")} }

free(A)
A closed

结构类型还可以用在稍微复杂一点的“复合类型”中,比如:

scala> trait X1; trait X2;

scala> def test(x: X1 with X2 { def close():Unit } ) = x.close

上面声明test方法参数的类型为:

X1 with X2 { def close():Unit }

表示参数需要符合特质X1和X2同时也要有定义close方法

复合类型

class A extends B with C with D with E

应该理解为 class A extends (B with C with D with E) 这叫做复合类型

也可以通过Type声明别名

scala> type X = X1 with X2
defined type alias X

scala> def test(x:X) = println("OK")
test: (x: X)Unit

scala> class A extends X1 with X2

scala> val a = new A

scala> test(a)
OK

Type 定义类型

type S = String

可以给 String类型起一个别名 S

可以用于抽象类型

scala> trait A { type T ; def foo(i:T) = print(i) }

scala> class B extends A { type T = Int }

scala> val b = new B

scala> b.foo(200)
200

scala> class C extends A { type T = String }

scala> val c = new C

scala> c.foo("hello")
hello

交集类型和联合类型

X with Y with Z 开发交集类型

X or Y or Z 是并集类型,但是scala目前并不支持,可以使用隐式转换来实现

class StringOrInt[T]
object StringOrInt {
  implicit object IntWitness extends StringOrInt[Int]
  implicit object StringWitness extends StringOrInt[String]
}

object Bar {
  def foo[T: StringOrInt](x: T) = x match {
    case _: String => println("str")
    case _: Int => println("int")
  }
}

泛型子类型 父类型

在Java泛型里表示某个类型是Test类型的父类型,使用super关键字:

<T super Test>

//或用通配符的形式:
<? super Test>

scala 中使用

[T >: Test]

//或用通配符:
[_ >: Test]

lower bound适用于把泛型对象当作数据的消费者的场景下:

def append[T >: String] (buf : ListBuffer[T])  = {  
                buf.append( "hi")
}

数组类型

协变 : A 是 B 的子类型, List[A] 也是 List[B] 的子类型

逆变 : A 是 B 的子类型, List[B] 是 List[A] 的子类型

在java中引用类型的数组类型是支持协变的, 即 String[] 类型是 Object[] 的子类型,

比如排序算法:

void sort(Object[] a, Comparator cmp) { … }

数组的协变被用来确保任意参数类型的数组都可以传入排序方法。随着java引入了泛型,sort方法可以用类型参数,因此数组的协变不再有用。只是考虑到兼容性。

scala里不支持数组的协变,以尝试保持比java更高的纯粹性。即 Array[String]的实例对象不能赋给Array[Any]类型的变量。

不同于java里其他泛型集合的实现,数组类型中的类型参数在运行时是必须的,即 [Ljava/lang/String 与 [Ljava/lang/Object 是两个不同的类型,不像 Collection<String> 与 Collection<StringBuilder> 运行时参数类型都被擦拭掉,成为Collection<Object>。

class List[T]  第一个是类型构造器,第二个是类型参数

java 不支持类型参数任然是 泛型, 但是scala支持类型参数是泛型

值类型

默认值类型 Int,Unit,Double ,创建好数组后,初始化 0 ,(), 0.0
进行初始化

然而自定义的值类型进行初始化,在创建一个数组后是用 null 进行填充的.

Null与Nothing

scala 类型系统以Any为根,分为AnyRel和AnyVal 两个分支体系,在AnyRef 底层有一个Null的子类型,它被当做AnyRef的子类型,在两个分支的最底层类型是Nothing,它被当做是AnyRef和AnyVal类型的类型.

Null类型只有一个唯一的值:null,可以被赋给所有的AnyRef类型变量

但null不可以赋值给AnyVal类型:

val i: Int = null
// java里,编译通过,运行失败,空指针异常
int i = (int)((Integer)null);

// scala里,把值为null的Integer拆箱为值类型Int是ok的,得到Int的默认值0
val i = null.asInstanceOf[java.lang.Integer].asInstanceOf[Int]

scala 和 java 的装箱拆箱的不同

在java里基本类型(primitive type) 与引用类型是有明确差异的,虽然提供了自动装箱拆箱的便捷,但在类型上两者是不统一的;而scala里修正这一点,Int类型不再区分int/Integer,类型一致,所以值为null的Integer在通过asInstanceOf[Int]时被当作一个未初始化的Int对待,返回了一个默认值Int(注:asInstanceOf不改变原值,返回一个新值)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容