Scala 类和对象

如果类没有内容(body),可以省略空的花括号,只写一行语句

class User
val user1 = new User

类可以带参数,类名称C之后圆括号内的参数,x称为类参数class parameter,Scala编译器会使用类参数创建出一个主构造函数paimary constructor

class C(x: R)

私有主构造函数,只在被类本身以及伴生对象访问

class class C(private x: R) 

Scala编译器会将编译类内部的任何代码,如果代码不是字段定义和方法定义,则被编译到主构造函数中
可以用_对成员初始变量进行初始化,对应为0或者null

class C(var x: R) {
  assert(x > 0, "positive please") //对参数的合法性进行检验
  var y = x
  val readonly = 5
  private var secret = _
  def this() = this(42)
} 

assert 方法位于scala.Predef对象内

辅助构造函数
主构造函数之外的构造函数称为辅助构造函数,辅助构造函数的第一个条语句必须是调用同类的其他构造函数,所有每个Scala构造器最终都会调用主构造器

  def this() = this(42)

私有构造函数
在类名称和参数列表之间添加关键字private/protected,来声明私有的或受保护的构造函数

class C private (var x: R)

隐式转换
implicit 修饰符告诉编译器在某些情况下自动应用它,它必须定义在作用域范围之内

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

创建一个隐式转换,在需要时自动将整数转换为有理数


抽象类

使用abstract来声明

abstract class D { ... }

继承
子类拥有父类非private的方法,如果不显示指明继承,默认继承scala.AnyRef,与java.lang.Object等同

class C extends D { ... }

方法重载
override关键词,进行函数重载,如果子类重写了父类的具体函数,必须添加override修饰符,否则就会出现编译错误

在Scala中,字段和方法属于同一个名称空间,可以使用字段覆盖无参数的方法

abstract class Element {
    def contents: Array[String]
}

class ArrayElement(conts: Array[String]) extends Element {
    val contents: Array[String] = conts
}

Java有四个名称空间是字段,方法,类型和包,相比之下,Scala有两个命名空间namespace

  • 值(字段,方法,包和单例对象)
  • 类型(类和特质名称)
    因此可以用字段覆盖无参数的方法,同一类内部的字段和方法名称不能相同

调用超类的构造函数
传递参数给超类的主构造函数,把参数放到超类名称后的括号内即可

class D(var x: R)
class C(x: R) extends D(x)

参数化字段 parametric field

一种简写方式,用于组合参数和字段,同时定义同名的参数和字段

//这里的conts只是构造函数的参数,类没有对应的字段
class ArrayElement(conts: Array[String]) extends Element {  
    val contents: Array[String] = conts
}
// 简写,自动生成同名的字段
class ArrayElement(
    val contents: Array[String]
) extends Element

参数前可以是valvarprivateprotectedoverried之类的修饰符

class Cat {
  val dangerous = false
}
class Tiger(
    override val dangerous: Boolean,
    private var age: Int
) extends Cat
//等价于
class Tiger(param1: Boolean, param2: Int) extends Cat {
    override val dangerous = param1
    private var age = param2
}

实际上如在出构造函数之外的地方使用构造参数,内部依然会把它转换为private val类型的字段

  class Foo(bar: Int){
    def funtion1(): Unit ={
      println(bar)
    }
  }

内部包含字段private val bar: Int,与class Foo(private val bar: Int)的区别在于没有对应的私有getter方法private int bar();生成


变量的Getter/Setter方法

Scal字段会自动生成getter和setter方法,val类型没有setter方法
Scala支持setter方法的名称为getter函数名后加_=,使用时可以对getter函数名直接赋值

class Test{
  private var _x = 0

  def x = _x //get方法
  def x_= (newValue: Int): Unit = { //set方法
    _x = newValue
  }
}

//使用方法
val test = new Test
test.x = 5
val x = test.x

Singleton Objects

Scala没有static成员,通过单例对象来实现类似功能,等同于把所有的静态成员都放到了单例对象中,可以通过名称直接调用它的方法,就像一个静态方法的集合

  • 它的定义类似于一个类的定义,不同的是它的关键字是object
  • object是只有一个实例的类,本身可以看做是一个惰性加载的val类型
  • 实际实现是一个合成类(synthetic class)实例,被类成员中的一个静态变量引用,编译产生的类名是对象名称加上美元符号SingletonObjectName$

单例对象和类的一个不同在于单例对象不能接收参数,而类可以。因为不能使用 new 来实例化一个单例对象,因此没有办法给它传递参数

Companion object

单例对象的名字和类名称一致的时候叫做伴生对象companion object,必须在同一个文件中定义类和它的伴生对象,他们可以互相访问对方的私有成员

standalone object

没有和类共享名称的单例对象叫做独立对象,为了运行一个Scala程序,必须提供一个独立对象,内部包含一个程序执行的入口函数def main(args: String) = {}

Scala每个源文件都默认包含java.langscala包,以及scala.Predef的单例对象
Predef中包含了许多有用的方法, 例如,printlnassert方法
同时Scala不要求 .scala文件名称对应内部的类,可以随意命名

通过混入scala.App类型的trait,定义应用程序对象,即在对象后添加extends App,放置在main方法中的代码直接放在单体对象的花括号之间,通过args字符串数组访问命令行参数即可


特质trait

封装字段和方法定义,类似Java的接口,使用extends或者with关键字,混入(mixin)到类中,数量没有限制
使用extends关键词,类隐式继承特质的超类(特质没有声明超类时,默认为AnyRef
如果类已经显示扩展超类,使用with

  • trait不能有类参数(传递到类的主构造函数的参数)
  • 超类调用是不确定的,动态变化的(trait超类的调用方式)
trait T1; trait T2
class C extends T1 with T2
class C extends D with T1 with T2

特质不仅可以有抽象方法,也可以包含具体方法

trait Ordered[A] extends Any with java.lang.Comparable[A] {
  def compare(that: A): Int
  def <  (that: A): Boolean = (this compare that) <  0
  def >  (that: A): Boolean = (this compare that) >  0
  def <= (that: A): Boolean = (this compare that) <= 0
  def >= (that: A): Boolean = (this compare that) >= 0
  def compareTo(that: A): Int = compare(that)
  def compareTo(that: A): Int = compare(that)
}

stackable modification 可堆叠的变化

特点

  • 特质指定超类,那么只能用于同样扩展该超类的类
  • 特质的抽象方法调用超类,特质中的super调用是动态绑定的,混入另一个特征或类后,才有具体的定义

abstract override修饰符组合,只能由于特质,它表明特质必须混入到有具体方法定义的类中

abstract class IntQueue {
  def get(): Int
  def put(x: Int)
}

import scala.collection.mutable.ArrayBuffer
class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]
  def get() = buf.remove(0)
  def put(x: Int) = { buf += x }
}

trait Doubling extends IntQueue {
  abstract override def put(x: Int) = { super.put(2 * x) }
}

trait Incrementing extends IntQueue {
  abstract override def put(x: Int) = { super.put(x + 1) }
}
trait Filtering extends IntQueue {
  abstract override def put(x: Int) = {
    if (x >= 0) super.put(x)
  }
}

val queue = (new BasicIntQueue with Filtering with Incrementing)

多个traits重载同一个方法,不同的次序会产生不同的类,优先级是从右向左,以类似栈的形式调用函数
类似多重继承,是利用线性化linearization算法解释超类

当用new实例化一个类时,Scala把这个类及其所有继承的类和特质以线性次序放在一起。 然后,每当其中一个类中调用super时,被调用的方法就是链中的下一个。 如果除最后一次调用之外的所有方法都调用super,那么最终结果就是是可堆叠行为

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

推荐阅读更多精彩内容

  • Scala与Java的关系 Scala与Java的关系是非常紧密的!! 因为Scala是基于Java虚拟机,也就是...
    灯火gg阅读 3,413评论 1 24
  • 类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图...
    Bloo_m阅读 314评论 0 0
  • 前面提到Scala比Java更加面向对象,这是因为Scala不允许类保护静态元素(静态变量或静态方法)。在Scal...
    MaLiang阅读 298评论 0 2
  • 有了前面的Scala基础,从本篇开始由浅到易逐步介绍Scala编程的各个方面,博客不可能做到面面俱到,还是希望你有...
    MaLiang阅读 223评论 0 2
  • 今天小巍一个人在医院,我却在上班,对不起.............. 2017年12月18,家里的小家伙,病理性骨...
    赵东伟同学阅读 59评论 0 0