Scala类与对象

Scala类与对象

类简介

简介

类是对象的蓝图。一旦你定义了类,就可以用关键字new根据类的蓝图创建对象。在类的定义里,可以放置字段和方法,这些被笼统地称为成员。对于字段,不管是val还是var定义的,都是指向对象的变量。对于方法,用def定义,包含了可执行代码。字段保留了对象的状态或数据,而方法使用这些数据执行对象的运算工作。当类被实例化的时候,运行时环境会预留一些内存来保留对象的状态映像——即变量的内容。

示例

创建类示例:

class SumAccumulator {
  var sum = 0
}

然后实例化两次:

val acc: SumAccumulator = new SumAccumulator
val csa: SumAccumulator = new SumAccumulator

这时内存里对象的状态映像如下:

由于字段sum是var类型而非val,所以sum可以被赋予新的Int类型的值:例如

acc.sum = 3

此时映像会变成:

Scala类的重要特性

访问修饰符

  • Public是Scala默认的访问级别

为了保证对象的健壮性,可以把类中字段变为私有的(private)以阻止外界直接对它访问。因为私有字段只能被定义成在同一类里的方法访问,所有跟新字段的代码将锁定在类里。要声明字段是私有的,可以把访问修饰符private放在字段的前面。

代码示例:

class SumAccumulator {
  private var sum = 0
}

使用private修饰后,任何从类外部对sum的访问都将失败

val acc: SumAccumulator = new SumAccumulator
acc.sum = 3    //编译不通过,因为sum是私有的

方法

1. Scala方法参数类型

Scala方法参数中的类型都是val而不是var类型

def add(a: Int, b: Int): Int = {
  a = a + b    //编译错误:Reassignment to val  (就是对val类型赋值的错误)
  a
}

2. Scala方法中return

Scala方法中的return可以去掉,从而简化代码

代码示例:

def numSum(num:Int):Int ={
  val sum = num + 10
  sum     //省略return关键字,简化代码
}

此时返回值就是sum

3. Scala方法中的“=”号

Scala方法中的“=”号非常重要:因为Scala编译器可以把任何类型转换为Unit,如果定义的函数中”=”号忘记了添加,那么Scala会默认它返回值为Unit类型。若你本来想返回一个String类型的值,由于没有添加”=”,String类型返回值会被转换为Unit类型而丢弃掉。

代码示例:

def printStr() {
  "这是String类型的返回值"
}

返回结果为:   ()

正确代码示例:

def printStr(): String = {
  "这是String类型的返回值"
}

返回结果为:    这是String类型的返回值

4. Scala方法表达式

假如某个方法仅计算单个结果的表达式,这可以去掉花括号,如果结果表达式很短,甚至可以把它放在def的同一行里。

代码示例:

def numSum(num:Int):Int = num + 10

5. Scala中分号推断

scala程序中,语句末尾的分号通常是可选的,若一行仅有一个语句也可以不加分号。不过,如果一行包含多条语句时,分号则是必须的。

不加分号:

if(x < 2)
  println("too small")
else
  println("ok")

必须加分号:

val x = 10; println(x)  //两个语句,必须加分号

Scala通常的风格是把操作符放在行尾而不是行头:

错误示例:

val x = 10;
val y = 3
val z = x //它会被编译器识别为z = x ; +y 两个语句
+y

打印结果:

10

正确示例:

val x = 10;
val y = 3
val z = x +
  y
println(z)

打印结果:

13

Scala分号推断规则:

  1. 疑问行由一个不能合法作为语句结尾的字结束,如句点或中缀操作符。
  2. 下一行开始于不能作为语句开始的词。
  3. 行结束于括号(...)或方框[...]内部,因为这些符号不能容纳多个语句。

6. Scala无参方法

调用Scala类中无参方法时,可以写上括号,也可以不写。对于类中的取值器来说,去掉()是不错的风格。

代码示例:

object exam1 {
  def main(args: Array[String]): Unit = {
    val per: Person = new Person
    per.talk()   //ok
    per.talk     //同样ok
  }
}

class Person {
  def talk(): Unit = println("Talking")
}

如果你想强制使用这种风格,可以在声明方法时不带()

代码示例:

per.talk() //此时这种写法是错误的
per.talk //OK的
class Person {
  def talk = println("Talking")
}

Scala类中getter和setter

getter和setter

Scala类中使用公有字段的话,任何人都可以修改这个字段,使得安全性大大降低。所以我们更倾向于使用getter和setter方法:

Scala对类中每个字段都提供了getter和setter方法,分别叫做age和age_=,

代码示例:

val per: Person = new Person
per.age = 18

class Person {
  var age = 0
}

如果想查看这些方法,可以先编译Person类,然后用javap查看字节码:

你可以自己重新定义getter和setter方法

代码示例:

object exam1 {
  def main(args: Array[String]): Unit = {

    val per: Person = new Person
    per.age = 18
    per.age = 16    //由于在setter里面控制了age不能变小,所以执行结果age不会变
    println(per.age)

    per.age = 19   //使用setter,赋予大于原来的age
    println(per.age)
  }
}

class Person {
  private var privateAge = 0  //变成私有变量并改名
  def age = privateAge
  def age_=(newAge: Int) {    // age_= 不能有空格
    if (newAge > privateAge) privateAge = newAge  //使得年龄不能变小
  }
}

打印结果为:

18
19

Scala中每个字段生成getter和setter的限制:

  1. 如果字段是私有的,则getter和setter方法也是私有的。
  2. 如果字段是val,则只有getter方法被生成。
  3. 如果你不需要任何getter或setter,可以将字段声明为private[this]

Scala在实现类中属性时的四个选择:

  1. 自动生成一个getter和setter。
  2. 自动生成一个getter。
  3. 自定义foo和foo_=方法。
  4. 自定义foo方法。

Bean属性

JavaBean规范把Java属性定义为一堆getFoo和setFoo方法。类似于Java,当你将Scala字段标注为 @BeanProperty时,getter和setter方法会自动生成。

代码示例:

import scala.beans.BeanProperty

object exam1 {
  def main(args: Array[String]): Unit = {

    val per: Person = new Person
    per.name = "zhagnsan"
    per.setName("lisi")    //BeanProperty生成的setName方法
    println(per.getName)   //BeanProperty生成的getName方法
  }
}

class Person {
  @BeanProperty var name:String = _

}

打印结果为:

Lisi

上述类Person中由@BeanProperty生成了四个方法:

1. name: String
2. name_= (newValue: String): Unit
3. getName(): String
4. setName (newValue: String): Unit

图示为针对字段生成的方法:

Scala类中构造器

和java或C++一样,Scala也可以有任意多的构造器。不过,Scala类有一个构造器比其他所有构造器都更为重要,它就是主构造器。除了主构造器外,Scala类还可以有任意多的辅助构造器。

辅助构造器

Scala中辅助构造器和Java或C++十分相似,只有两处不同:

  1. 辅助构造器的名称为this。
  2. 每一个辅助构造器都必须以一个对先前已定义的其他辅助构造器或主构造器的调用开始

这里有一个带有两个辅助构造器的类。

代码示例:

object exam1 {
  def main(args: Array[String]): Unit = {

    val per1: Person = new Person   //主构造器
    val per2: Person = new Person("Bob")   //第一个辅助构造器
    val per3: Person = new Person("Bob",18)  //第二个辅助构造器
  }
}

class Person {
  private var name = ""
  private var age = 0

  //一个辅助构造器
  def this(name: String) {
    this() //调用主构造器
    this.name = name
  }

  //另一个辅助构造器
  def this(name: String, age: Int) {
    this(name) //调用前一个辅助构造器
    this.age = age
  }
}

主构造器

在Scala中,每个类都有主构造器。主构造器并不以this方法定义,而是与类定义交织在一起。

主构造器的参数直接放在类名之后

代码示例:

object exam1 {
  def main(args: Array[String]): Unit = {
    val per: Person = new Person("Bob", 18) //使用主构造器实例化对象
    println(per.name + " : " + per.age)
  }
}

class Person(val name: String, val age: Int) {
  //产生私有的name和age,没有setter
  //.....
}

打印结果:

Bob : 18

上述简短的Person类定义极大简化了相同功能的Java代码:

与上例相同功能的Java代码示例:

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String name() {
        return this.name;
    }

    public int age() {
        return this.age;
    }
}

Scala主构造器定义的所有语句都会执行

代码示例:

class Person(val name: String, val age: Int) {
  //产生私有的name和age,没有setter
  println("主构造器定义的所有语句都会执行")   //每次使用主构造器时都会执行

  def description = name + "is" + age + "years old"
}

不同类型的主构造器参数对应会生成的字段和方法:

如果想让主构造器变成私有的,可以像这样放置private关键字:

class Person private (val name: String, val age: Int) {
  //......
}

这样一来,类用户就必须通过辅助构造器来构造Person对象了。

Scala嵌套类

在Scala中,你几乎可以在任何语法结构中内嵌任何语法构造。你可以在函数中定义函数,在类中定义类。

代码示例:

class Network {

  //在Network类中定义类Member
  class Member(val name: String) {
    val contacts = new ArrayBuffer[Member]
  }

  private val members = new ArrayBuffer[Member]

  def join(name: String) = {
    val m = new Member(name)
    members += m
    m
  }
}

考虑有如下两个网络:

val chatter = new Network
val myFace = new Network

在Scala中,每个实例都有它自己的Member类,就和它们有自己的members字段一样。也就是说chatter.Member和myFace.Member是不同的两个类。

作用:拿网络示例来说,你可以在各自的网络中添加成员,但是不能跨网添加成员。

代码示例:

val chatter = new Network
val myFace = new Network
val fred = chatter.join("Fred")
val wilma = chatter.join("wilma")
fred.contacts += wilma  //OK
val barney = myFace.join("Barney")

//错误:不能将一个myFace.Member添加到chatter.Member元素缓冲中
fred.contacts += barney

在嵌套类中,你可以通过 外部类.this 的方式来访问外部类的this引用,就像Java那样。

class Network(val name: String) {
  //在Network类中定义类Member
  class Member(val name: String) {
    //....
    def description = name + "inside" + Network.this.name
  }
}

如果你觉得需要,也可以使用如下语法建立一个指向该引用的别名:

class Network(val name: String) { outer =>
  //在Network类中定义类Member
  class Member(val name: String) {
    //....
    def description = name + "inside" + outer.name
  }
}

上述语法使得outer变量指向Network.this。对这个变量,你可以使用任何合法的名称。

时间: 2024-10-16 10:15:30

Scala类与对象的相关文章

[Scala基础系列 06]Scala类和对象

1.类和构造函数 Scala中的类,基本概念与其他面向对象语言是一致的,不过在语法上有些不一样的地方.与Java等语言相比,Scala的类语法更简洁,使用起来也更方便. 1.1.类的基本语法 我们先来看一个简单的类定义和使用的代码. class ScoreCalculator { private var total, count = 0 def report(score: Int) { total += score count += 1 } def score = if (count == 0)

scala 类,伴生对象

1.属性的定义 编写一个PersonS类,并在其中定义一些属性,通过PersonS.scala 编译后的情况查看,可以知道不同修饰符修饰的属性分别会生成什么方法(set,get) package com.jason.qianfeng class Persons { //val修饰的属性系统自动生成get方法 val id: String = "1234" //var 修饰的属性系统会自动生成set 和 get 方法 var name:String = "" // p

scala学习-类与对象

类 / 对象 [<快学Scala>笔记] 一.类 1.Scala中的类是公有可见性的,且多个类可以包含在同一个源文件中: 1 class Counter{ 2 private var value = 0 //类成员变量必须初始化,否则报错 3 4 def increment(){ //类中的方法默认是公有可见性 5 value += 1 6 } 7 8 def current() = value //对于类中的“取值方法”,在定义时可省略掉括号,直接 def current = value 9

Scala 编程(二)类和对象

类,字段和方法 类是对象的蓝图.一旦定义了类,就可以用关键字new从类的蓝图里创建对象,类的定义: class ChecksumAccumulator { // class definition goes here } 就能创建对象: scala> new ChecksumAccumulator res0: ChecksumAccumulator = [email protected] 类定义里,可以放置字段和方法,这些被笼统地称为成员:member.字段,不管是用 val 或是用 var 定义

scala快速学习笔记(二):控制结构,类和对象

IV.控制结构 1.if/else 除基本用法外,if/else语句能用来赋值,进而代替?:运算符.这得益于在Scala中,每个语句块都有值,就是该语句块最后一个语句的值.请看下面的代码. def abs(x: Int) = if(x < 0) -x else x 2.与If语句不同,While语句本身没有值,即整个While语句的结果是Unit类型的(). PS:scala中赋值语句也没有值. 3.用于迭代一个集合的for语句,格式为for(item <- collection).一些col

spark快速开发之scala基础之3类,对象,特征

类 scala的类定义非常灵活 class test4 class test2{} class test3(x:Int) 定义一个带构造函数的类 class Point (x : Int,y : Int){ def add() : Int = { x1 + y2 } } 通过this来重写构造函数 def this(X1 : Int){ this(X1,1) } def this(X2 : String){ this(0,1) } 除了重写构造函数,还可以当作当前对象的引用. def add(x

Scala 系列(八)—— 类和对象

一.初识类和对象 Scala 的类与 Java 的类具有非常多的相似性,示例如下: // 1. 在 scala 中,类不需要用 public 声明,所有的类都具有公共的可见性 class Person { // 2. 声明私有变量,用 var 修饰的变量默认拥有 getter/setter 属性 private var age = 0 // 3.如果声明的变量不需要进行初始赋值,此时 Scala 就无法进行类型推断,所以需要显式指明类型 private var name: String = _

Scala中包、类、对象、成员访问权限理解

本文通过下面一个程序简单分析下包.类.对象访问权限的情况: package spark {   package navigation {     private[spark] class Navigator {       protected[navigation] def useStartChar() = println("navigation")       class LegOfJourney {         private[Navigator] val distance =

atitit.编程语言&#160;类与对象的&#160;扩展机制.doc

atitit.编程语言 类与对象的 扩展机制.doc 1.1. Java 下一代: 没有继承性的扩展1 1.2. 继承1 1.3. 使用cglib动态为Java类添加方法1 1.4. 工具类 1 1.5. Wrap 包装类  装饰器模式2 1.6. 扩展方法 (其实就是工具类的语法糖)2 1.7. Scala 的隐式转换2 1.8. 类别类.ExpandoMetaClass2 1.1. Java 下一代: 没有继承性的扩展 Groovy.Scala 和 Clojure 提供了许多扩展机制,但继承