【Scala】Scala之Methods(上)

简介: 前面学习了Scala的Class,下面接着学习Method(方法)。

一、前言


  前面学习了Scala的Class,下面接着学习Method(方法)。


二、Method


  Scala的方法与Java的方法类似,都是添加至类中的行为,但是在具体的实现细节上差异很大,下面展示一个参数为整形,返回值为String的方法定义 

// java
public String doSomething(int x) {
    // code here
}
// scala
def doSomething(x: Int): String = {
    // code here
}

Scala中的方法可以写的更为简洁,如下

def plusOne(i: Int) = i + 1

 将参数值加1后返回,不用显示定义返回值类型,除了已经给出的差别,还有其他差别如下

    · 指定方法访问控制(可见性)

    · 为方法参数设置默认值的能力

    · 调用方法时指定方法参数名称的能力

    · 声明方法抛出的异常

    · 在方法中使用var类型的字段

  2.1 控制方法的范围

  1. 问题描述

  Scala的方法默认为public的,你需要像Java一样控制方法的范围

  2. 解决方案

  Scala提供了如下范围控制选项

    · 对象私有范围的

    · 私有的

    · 受保护的

    · 包级别的

    · 指定包级别的

    · 公有的

  最严格的访问就是将方法定义为对象私有的,其只能在当前对象上被调用,其他同类型对象无法访问,在方法前面添加private[this]即可 

private[this] def isFoo = true

 在如下示例中,doFoo的参数为Foo实例,但是isFoo被定义为对象私有方法,如下代码编译不成功

  1.png

  这是因为other无法访问isFoo方法,该方法被定义为只有this(当前对象)可以访问

  可以将方法定义为private,这样当前对象可以访问,并且同类型的其他对象也可以访问

  2.png

  当定义为private时,子类无法访问,如下示例编译不会通过

  3.png

  将heartBeat定义为protected之后则可通过编译

  4.png

  Scala中的protected含义与Java不太相同,其在同一个包的其他类无法访问该protected方法,如下示例 

package world {
    class Animal {
        protected def breathe {}
    }
    class Jungle {
        val a = new Animal
        a.breathe // error: this line won't compile
    }
}

 编译时报错如下

  5.png

  表示Jungle类无法访问同包下的Animal类的方法

  为了是方法对于同包下的其他类可见,可以使用private[packageName]来修饰方法 

package model {
    class Foo {
        private[model] def doX {}
        private def doY {}
    }
    class Bar {
        val f = new Foo
        f.doX // compiles
        f.doY // won't compile
    }
}

 运行结果如下

  6.png

  除了让方法在同包下可见,Scala还可以让包在类继承结构中的不同层级下可见 

package com.hust.grid.model {
    class Foo {
        private[model] def doX {}
        private[grid] def doY {}
        private[hust] def doZ {}
    }
}
import com.hust.grid.model._
package com.hust.grid.view {
    class Bar {
        val f = new Foo
        f.doX // won't compile
        f.doY
        f.doZ
    }
}
package com.hust.common {
    class Bar {
        val f = new Foo
        f.doX // won't compile
        f.doY // won't compile
        f.doZ
    }
}

其中doX在model包下其他类中可见,doY在grid包下其他类中可见,doZ在hust包下其他类中可见

  如果方法没有修饰符,其就是public的,下面示例中任何类都可以调用doX方法  

package com.hust.grid.model {
    class Foo {
        def doX {}
    }
}
package org.xyz.bar {
    class Bar {
        val f = new com.hust.grid.model.Foo
        f.doX
    }
}

3. 讨论

  Scala中的访问控制符比Java的要稍微复杂点,需要不断体会和使用

  2.2 调用超类的方法

  1. 问题描述

  为了保持代码的简洁性,你需要调用父类定义的方法

  2. 解决方案

  在基础使用上,Scala与Java一样,使用super指代超类,然后使用方法名指代具体方法

class WelcomeActivity extends Activity {
    override def onCreate(bundle: Bundle) {
        super.onCreate(bundle)
        // more code here ...
    }
}

如果类继承了多个traits,并且这些traits实现了相同的方法,这时你不仅可以选择方法,并且还可以选择哪个traits 

trait Human {
    def hello = "the Human trait"
}
trait Mother extends Human {
    override def hello = "Mother"
}
trait Father extends Human {
    override def hello = "Father"
}

 你可以使用如下不同的方法调用hello方法 

class Child extends Human with Mother with Father {
    def printSuper = super.hello
    def printMother = super[Mother].hello
    def printFather = super[Father].hello
    def printHuman = super[Human].hello
}

 可以进行如下测试

object Test extends App {
    val c = new Child
    println(s"c.printSuper = ${c.printSuper}")
    println(s"c.printMother = ${c.printMother}")
    println(s"c.printFather = ${c.printFather}")
    println(s"c.printHuman = ${c.printHuman}")
}

 运行结果如下 

c.printSuper = Father
c.printMother = Mother
c.printFather = Father
c.printHuman = the Human trait

当类继承多traits并且有多个相同方法时,可以使用super[traitName].methodName 来调用不同父类中的相同方法

  值得注意的是,其无法使用到父类的继承结构(如父类的父类),其只能调用其直接继承的父类的方法,如下例所示,super[Animal].walk编译报错 

trait Animal {
    def walk { println("Animal is walking") }
}
class FourLeggedAnimal extends Animal {
    override def walk { println("I'm walking on all fours") }
}
class Dog extends FourLeggedAnimal {
    def walkThenRun {
        super.walk // works
        super[FourLeggedAnimal].walk // works
        super[Animal].walk // error: won't compile
    }
}

 由于Dog并为直接继承Animal,因此不能使用super[Animal].walk来调用Animal的方法

  2.3 设置方法参数的默认值

  1. 问题描述

  你想要定义方法参数值的默认值,以便在调用方法时不用显示定义该方法参数

  2. 解决方案

  在方法签名中指定默认值,如下所示 

class Connection {
    def makeConnection(timeout: Int = 5000, protocol: = "http") {
        println("timeout = %d, protocol = %s".format(timeout, protocol))
        // more code here
    }
}

timeout的默认值为5000,protocal的默认值为"http",可以通过如下方法调用该方法 

c.makeConnection()
c.makeConnection(2000)
c.makeConnection(3000, "https")

如果你喜欢指定参数名时,可以使用如下方式

c.makeConnection(timeout=10000)
c.makeConnection(protocol="https")
c.makeConnection(timeout=10000, protocol="https")

 3. 讨论

  如同构造函数参数一样,你可以为方法参数设置默认值,方法中参数的赋值从左到右,使用如下方法可以使用timeout和protocal的默认值

c.makeConnection()

可以设置timeout值为2000,而protocal使用默认值  

c.makeConnection(2000)

 可以设置同时设置timeout和protocal的值

c.makeConnection(2000, "https")

但是通过上述方法无法单独设置protocal的值,可以这样单独设置protocal的值,而timeout默认为5000

c.makeConnection(protocol="https")

当你的方法中既有默认值也有非默认值,你需要将由默认值的参数放在最后

  7.png

  可以上述调用都会报错,重新调整参数位置即可

  8.png

目录
相关文章
|
存储 Java API
【Scala】Scala之Methods(下)
前面学习了Scala的Class,下面接着学习Method(方法)。
102 0
【Scala】Scala之Methods(下)
|
SQL 消息中间件 分布式计算
如何查看spark与hadoop、kafka、Scala、flume、hive等兼容版本【适用于任何版本】
如何查看spark与hadoop、kafka、Scala、flume、hive等兼容版本【适用于任何版本】
917 0
如何查看spark与hadoop、kafka、Scala、flume、hive等兼容版本【适用于任何版本】
|
3月前
|
分布式计算 资源调度 Java
Scala+Spark+Hadoop+IDEA实现WordCount单词计数,上传并执行任务(简单实例-下)
Scala+Spark+Hadoop+IDEA实现WordCount单词计数,上传并执行任务(简单实例-下)
37 0
|
3月前
|
分布式计算 Hadoop Scala
Scala +Spark+Hadoop+Zookeeper+IDEA实现WordCount单词计数(简单实例-上)
Scala +Spark+Hadoop+Zookeeper+IDEA实现WordCount单词计数(简单实例-上)
34 0
|
4月前
|
SQL 存储 分布式计算
在scala中使用spark
在scala中使用spark
227 0
|
4月前
|
分布式计算 Java Scala
spark 与 scala 的对应版本查看、在idea中maven版本不要选择17,弄了好久,换成11就可以啦
spark 与 scala 的对应版本查看、.在idea中maven版本不要选择17,弄了好久,换成11就可以啦
302 2
|
4月前
|
分布式计算 Java Scala
Spark编程语言选择:Scala、Java和Python
Spark编程语言选择:Scala、Java和Python
Spark编程语言选择:Scala、Java和Python
|
4月前
|
分布式计算 数据处理 Scala
Spark 集群和 Scala 编程语言的关系
Spark 集群和 Scala 编程语言的关系
|
存储 分布式计算 Scala
Spark-RDD 键值对的操作(Scala版)
Spark-RDD 键值对的操作(Scala版)