参考教程:https://yq.aliyun.com/topic/69
spark-shell是Spark交互式运行模式,提供了交互式编程,边敲代码边执行,不需要创建程序源文件,方便调试程序,有利于快速学习Spark。
[root@node1 spark-2.2.0]# bin/spark-shell
Using Spark's default log4j profile: org/apache/spark/log4j-defaults.properties
Setting default log level to "WARN".
To adjust logging level use sc.setLogLevel(newLevel). For SparkR, use setLogLevel(newLevel).
17/09/03 06:32:38 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
17/09/03 06:32:56 WARN ObjectStore: Failed to get database global_temp, returning NoSuchObjectException
Spark context Web UI available at http://192.168.80.131:4040
Spark context available as 'sc' (master = local[*], app id = local-1504434761542).
Spark session available as 'spark'.
Welcome to
____ __
/ __/__ ___ _____/ /__
_\ \/ _ \/ _ `/ __/ '_/
/___/ .__/\_,_/_/ /_/\_\ version 2.2.0
/_/
Using Scala version 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_112)
Type in expressions to have them evaluated.
Type :help for more information.
scala>
Spark内置了Scala环境,进入spark-shell后可以看到scala>
,可以直接输入scala语句,回车即执行。
Scala 极度重用了 Java 类型,Scala 的 Int 类型代表了 Java 的原始整数类型 int,Float 代表了 float,Boolean 代表了 boolean,数组被映射到 Java 数组。Scala 同样重用了许多标准 Java 库类型。例如,Scala 里的字符串文本是 Java.lang.String,而抛出的异常必须是 java.lang.Throwable 的子类。
scala> var x:Int =10
x: Int = 10
scala> var y:Double =3.14
y: Double = 3.14
scala> var s:String ="Hello,Scala!"
s: String = Hello,Scala!
scala> var b:Boolean=true
b: Boolean = true
scala>
备注:Scala语句的分号是可选的,且通常不写
在 Scala 中,使用关键词 “var” 声明变量,使用关键词 “val” 声明常量。在 Scala 中声明变量和常量不一定要指明数据类型,在没有指明数据类型的情况下,其数据类型是通过变量或常量的初始值推断出来的。
所以,如果在没有指明数据类型的情况下声明变量或常量必须要给出其初始值,否则将会报错。
scala> var x=1000
x: Int = 1000
scala> var y=3.14
y: Double = 3.14
scala> val s="hello,world"
s: String = hello,world
scala>
备注:val 变量的值只能初始化一次,再次赋值会发生错误,var 和 Java 的变量相同,可以随时修改。val 是函数式编程的风格,变量一旦赋值就不要再做修改。
(1)算术运算
scala> 1+2
res1: Int = 3
scala> 2*3-5/2
res2: Int = 4
scala> 7%3
res3: Int = 1
scala>
(2)关系运算
scala> var a=5
a: Int = 5
scala> var b=3
b: Int = 3
scala> a==b
res7: Boolean = false
scala> a>=b
res8: Boolean = true
scala> a!=b
res9: Boolean = true
scala>
(3)逻辑运算
scala> var a=true;
a: Boolean = true
scala> var b=false;
b: Boolean = false
scala> a && b
res4: Boolean = false
scala> a || b
res5: Boolean = true
scala> !(a&&b)
res6: Boolean = true
scala>
(4)赋值运算符
scala> var x=2
x: Int = 2
scala> x+=3
scala> println(x)
5
scala> x*=3
scala> println(x)
15
scala>
备注:
(5)运算符重载
Scala允许方法调用形式a.fun(b)
简写为a fun b
。
scala> 1.to(10)
res15: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> 1 to 10
res16: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
scala> "hello" + ",world"
res17: String = hello,world
scala> "hello".+(",world")
res18: String = hello,world
scala>
也就是说
scala> var x=3
x: Int = 3
scala> if(x<10)
| println("x<10")
x<10
scala> if(x<10){
| println("x<10")
| }else{
| println("x>10")
| }
x<10
scala>
scala> var x=10
x: Int = 10
scala> if(x<0){
| println("x<0")
| }else if(x<10){
| println("0<=x<10")
| }else{
| println("x>=10")
| }
x>=10
scala>
(1)while循环
scala> var i=1
i: Int = 1
scala> while(i<=100){
| sum+=i
| i=i+1
| }
scala> println(sum)
5050
scala>
(2)for循环
Scala的for循环与Java增强型for循环类似,基本形式是for a <- 集合
,a相当于集合的通项元素,用于遍历集合,<-
箭头符号类似于Java增强型for循环的冒号,<-表示生成器。
scala> var sum=0
sum: Int = 0
scala> for(i <- 1 to 100){
| sum+=i
| }
scala> println(sum)
5050
scala>
备注:Scala在for循环中对循环变量i的赋值用了“<-”符号,1 to 100指定了一个范围
在scala中还有一个和上面的to关键字有类似作用的关键字until,它的不同之处在于不包括最后一个元素
scala> for(i <- 1 until 10) {
| println("i is " + i);
| }
i is 1
i is 2
i is 3
i is 4
i is 5
i is 6
i is 7
i is 8
i is 9
scala>
首先,函数/变量同是一等公民,函数与变量同等地位,函数的定义可以单独定义,可以不依赖于类、接口或者object,而且独立存在,独立使用,并且可以赋值给变量。
Spark当中的计算都是用scala函数式编程来做。
(1)库函数
import scala.math._
import scala.math._
scala> val x=2
x: Int = 2
scala> sqrt(x)
res4: Double = 1.4142135623730951
scala>
备注:在Scala中,_字符是“通配符”,类似Java中的*
(2)自定义函数
函数的定义用 def 开始。每个函数参数后面必须带前缀冒号的类型标注,因为 Scala 编译器没办法推断函数参数类型。Scala 函数定义格式如下:
def functionName ([参数列表]) : [return type] = {
function body
return [expr]
}
定义一个求解最大值的函数
scala> def max(x: Int, y: Int): Int = if(x < y) y else x
max: (x: Int, y: Int)Int
scala> max(3,5)
res9: Int = 5
scala>
备注:Scala函数可以没有return 语句,默认返回最后一个值。
如果函数的参数在函数体内只出现一次,则可以使用下划线代替
scala> def mul(x:Int,y:Int)=x*y
mul: (x: Int, y: Int)Int
scala> mul(2,3)
res26: Int = 6
scala> def mul=(_:Int)*(_:Int)
mul: (Int, Int) => Int
scala> mul(3,4)
res27: Int = 12
scala>
(3)可变参数
Scala允许指定函数的最后一个参数可重复。
scala> def prints(args:String*)={
| for(arg <- args){
| println(arg)
| }
| }
prints: (args: String*)Unit
scala> prints("aa","bb","cc")
aa
bb
cc
scala>
备注:如果函数没有返回值,可以返回为 Unit,这个类似于 Java 的 void
(4)函数赋值
可以将一个函数赋值给一个变量, val 变量名 = 函数名+空格+_
这里函数名后面必须要有空格,表明是函数的原型
scala> val fmax=max _
fmax: (Int, Int) => Int =
scala> fmax(3,5)
res7: Int = 5
scala>
(5)匿名函数
匿名函数格式: val 变量名 = (参数:类型) => 函数体
scala> var increase = (x: Int) => x + 1
increase: Int => Int =
scala> var n=1;
n: Int = 1
scala> println(increase(n))
2
scala>
程序说明:
(x: Int) => x + 1
定义了一个匿名函数,=>表示对左边的参数进行右边的加工(6)高阶函数
因为函数的参数可以是变量,而函数又可以赋值给变量,即函数和变量地位一样,所以函数参数也可以是函数。Scala 中允许使用高阶函数, 高阶函数可以使用其他函数作为参数,或者使用函数作为输出结果。
普通函数的定义语法如下:
def funName(para1:Type1,para2:Type2):Type = { do some things }
高阶函数其实就是普通函数中的参数进一步推广了,高阶函数的参数可以是一个函数,参数名就是函数名,那么该特殊参数对应的类型怎么写呢?这样就把问题转化为寻找函数的类型的问题。函数的类型,其实就是输入输出的类型。
请看下面例子:
scala> import scala.math._
import scala.math._
scala> def valueFor(f:(Double)=>Double,value:Double)={
| f(value)
| }
valueFor: (f: Double => Double, value: Double)Double
scala> valueFor(ceil _,0.25)
res1: Double = 1.0
scala> valueFor(sqrt _,0.25)
res2: Double = 0.5
scala>
说明:
def valueFor(f:(Double)=>Double,value:Double)=f(value)
再看一个例子:
map方法接受一个函数参数,将它应用到数组中的每个元素,返回新的数组。
scala> import scala.math._
import scala.math._
scala> val num = 3.14
num: Double = 3.14
scala> val func = ceil _
func: Double => Double =
scala> val array = Array(1.0,3.14,4).map(func)
array: Array[Double] = Array(1.0, 4.0, 4.0)
scala> for(i<-array)print(i+" ")
1.0 4.0 4.0
scala>
(7)闭包
闭包可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
scala> var factor = 3
factor: Int = 3
scala> val multiplier = (i:Int) => i * factor
multiplier: Int => Int =
scala> println(multiplier(1))
3
scala> println(multiplier(2))
6
scala>
(8)柯里化(Currying)
柯里化函数是将原来接手两个参数的函数转变成新的接收一个参数的函数过程。新函数返回一个以原有第二个参数作为参数的函数。
柯里化函数定义
scala> def mul(x:Int)=(y:Int)=>x*y
mul: (x: Int)Int => Int
scala> mul(2)(3)
res19: Int = 6
scala> (mul(2))(3)
res23: Int = 6
scala>
说明:mul(2)(3)实际上是按照(mul(2))(3)形式计算的,mul(2)的结果(y:Int)=>2*y,这个新函数又接收参数3得到结果6。
Scala可以简写柯里化函数
scala> def mul(x:Int)(y:Int)=x*y
mul: (x: Int)(y: Int)Int
scala> mul(5)(3)
res20: Int = 15
再看一个例子
scala> def strcat(s1: String)(s2: String) = s1 + s2
strcat: (s1: String)(s2: String)String
scala> strcat("hello")("world")
res22: String = helloworld
scala>
scala> val msg = "hello"
msg: String = hello
scala> println(msg.length)
5
scala> println(msg.charAt(0))
h
scala> println(msg.compareTo("hi"))
-4
scala> println(msg.equals("hello"))
true
scala> val s=msg+",spark"
s: String = hello,spark
scala> println(s.substring(6))
spark
scala>
scala> var a1 = Array("QQ", "Baidu", "Google")
a1: Array[String] = Array(QQ, Baidu, Google)
scala> for(x<-a1)println(x)
QQ
Baidu
Google
scala> a1.foreach(x => println(x))
QQ
Baidu
Google
scala> a1.foreach(println(_))
QQ
Baidu
Google
scala> a1.foreach(println)
QQ
Baidu
Google
scala> var a2 =new Array[String](3)
a2: Array[String] = Array(null, null, null)
scala> array(0)="hello"
scala> a2(0)="hello"
scala> a2(1)="spark"
scala> a2(2)="!"
scala> println(a2(1))
spark
scala>
Array是定长数组,而ArrayBuffer是可变数组。ArrayBuffer对应于Java中的ArrayList。
scala> import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.ArrayBuffer
scala> val ab=ArrayBuffer[Int]()
ab: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer()
scala> ab += 1
res7: ab.type = ArrayBuffer(1)
scala> ab += (2,3,4,5)
res8: ab.type = ArrayBuffer(1, 2, 3, 4, 5)
scala> val array=Array(7,11,13,17)
array: Array[Int] = Array(7, 11, 13, 17)
scala> ab ++= array
res9: ab.type = ArrayBuffer(1, 2, 3, 4, 5, 7, 11, 13, 17)
scala> ab.foreach(println)
1
2
3
4
5
7
11
13
17
scala> val a1=ab.toArray
a1: Array[Int] = Array(1, 2, 3, 4, 5, 7, 11, 13, 17)
scala> val buffer=a1.toBuffer
buffer: scala.collection.mutable.Buffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 7, 11, 13, 17)
scala>
备注:
Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。。
列表的元素类型 T 可以写成 List[T]。
Scala的List,scala.List,不同于Java的java.util.List,总是不可变的(而Java的List可变)。更通常的说法,Scala的List是设计给函数式风格的编程用的。
scala> val fruit: List[String] = List("apples", "oranges", "pears")
fruit: List[String] = List(apples, oranges, pears)
scala> println(fruit(0))
apples
scala> println(fruit.head)
apples
scala> println(fruit.tail)
List(oranges, pears)
scala> println(fruit.isEmpty)
false
scala> fruit.length
res24: Int = 3
scala> fruit.foreach(x => println(x))
apples
oranges
pears
scala> fruit.foreach(println)
apples
oranges
pears
scala>
可以使用 ::: 运算符或 List.:::() 方法或 List.concat() 方法来连接两个或多个列表
Nil 也可以表示为一个空列表。
scala> val newFruit="bananas"::fruit
newFruit: List[String] = List(bananas, apples, oranges, pears)
scala> println(newFruit(0))
bananas
scala>
scala> val nums =List(-19,-7,0,3,11,19)
nums: List[Int] = List(-19, -7, 0, 3, 11, 19)
scala> nums.filter(_>0)
res30: List[Int] = List(3, 11, 19)
scala> nums.exists(_<0)
res31: Boolean = true
scala> nums.partition(_>0)
res34: (List[Int], List[Int]) = (List(3, 11, 19),List(-19, -7, 0))
scala>
说明:
集合中使用下划线是最常用的形式,下划线代表了集合中的“某(this)”一个元素。nums.filter(_>0)
等价于nums.filter(x=>x>0)
,其中x=>x>0是匿名函数,且参数在函数体中只出现一次,可以简写成_>0
。
与列表一样,元组也是不可变的,但与列表不同,元组可以包含不同类型的元素。而列表应该是List[Int]或List[String]的样子,元组可以同时拥有Int和String。元组很有用,比方说,如果你需要在方法里返回多个对象。Java里你将经常创建一个JavaBean样子的类去装多个返回值,Scala里你可以简单地返回一个元组。而且这么做的确简单:实例化一个装有一些对象的新元组,只要把这些对象放在括号里,并用逗号分隔即可。一旦你已经实例化了一个元组,你可以用点号,下划线和一个基于1的元素索引访问它。
scala> val pa = (40,"Foo")
pa: (Int, String) = (40,Foo)
scala> val pair = (40,"Foo")
pair: (Int, String) = (40,Foo)
scala> println(pair)
(40,Foo)
scala> println(pair._1)
40
scala> println(pair._2)
Foo
scala>
你或许想知道为什么你不能像访问List里的元素那样访问元组的,就像pair(0)。那是因为List的apply方法始终返回同样的类型,但是元组里的或许类型不同。这些_N数字是基于1的,而不是基于0的,因为对于拥有静态类型元组的其他语言,如Haskell和ML,从1开始是传统的设定。
Scala映射(Map)是一组键/值对的对象。 任何值都可以根据键来进行检索。键在映射中是唯一的,但值不一定是唯一的。映射也称为哈希表。映射有两种,不可变的和可变的。可变对象和不可变对象之间的区别在于,当对象不可变时,对象本身无法更改。
默认情况下,Scala使用不可变映射(Map)。如果要使用可变集合(Set),则必须明确导入scala.collection.mutable.Map类。如果想同时使用可变的和不可变映射(Map),那么可以继续引用不可变映射(Map),但是可以将mutable集合引用mutable.Map。
scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map
scala> var map = Map(1 -> "a", 2 -> "b", 3 -> "c")
map: scala.collection.mutable.Map[Int,String] = Map(2 -> b, 1 -> a, 3 -> c)
scala> println(map.keys)
Set(2, 1, 3)
scala> println(map.values)
HashMap(b, a, c)
scala> println(map.isEmpty)
false
scala> map += (4 -> "d")
res12: scala.collection.mutable.Map[Int,String] = Map(2 -> b, 4 -> d, 1 -> a, 3 -> c)
scala> map.foreach(value => print(value + " "))
(2,b) (4,d) (1,a) (3,c)
scala>
总结:
scala提供了许多用于添加和移除元素的操作符,总结如下。
任何一种函数式语言中,都有map函数与faltMap这两个函数
scala> val nums=List(1,2,3,4)
nums: List[Int] = List(1, 2, 3, 4)
scala> nums.map(x=>2+x)
res24: List[Int] = List(3, 4, 5, 6)
scala> nums.map(_+1)
res25: List[Int] = List(2, 3, 4, 5)
scala>
scala> val data = List("Hadoop","Java","Spark")
data: List[String] = List(Hadoop, Java, Spark)
scala> println(data.flatMap(_.toList))
List(H, a, d, o, o, p, J, a, v, a, S, p, a, r, k)
scala>
(1)模式匹配
模式匹配包括一系列备选项,每个替代项以关键字大小写为单位。每个替代方案包括一个模式和一个或多个表达式,如果模式匹配,将会进行评估计算。箭头符号=>将模式与表达式分离。
scala> def matchTest(x: Int): String = x match {
| case 1 => "one"
| case 2 => "two"
| case _ => "many"
| }
matchTest: (x: Int)String
scala> matchTest(1)
res37: String = one
scala> matchTest(2)
res38: String = two
scala> matchTest(3)
res39: String = many
scala>
(2)正则表达式
scala.util.matching包中提供的Regex类支持和实现正则表达式。
以下实例演示了使用正则表达式查找单词 Scala
scala> import scala.util.matching.Regex
import scala.util.matching.Regex
scala> val pattern = "Scala".r
pattern: scala.util.matching.Regex = Scala
scala> val str = "Scala is Scalable and cool"
str: String = Scala is Scalable and cool
scala> println(pattern findFirstIn str)
Some(Scala)
scala>
说明:
你可以使用 mkString( ) 方法来连接正则表达式匹配结果的字符串,并可以使用管道(|)来设置不同的模式
scala> val pattern = new Regex("(S|s)cala")
pattern: scala.util.matching.Regex = (S|s)cala
scala> val str = "Scala is scalable and cool"
str: String = Scala is scalable and cool
scala> println((pattern findAllIn str).mkString(","))
Scala,scala
scala>
程序说明:
- (S|s)cala
表示首字母可以是大写 S 或小写 s
- mkString(“,”)使用逗号 , 连接返回结果
scala> val pattern = """(\d{1,3}\.){3}\d{1,3}""".r
pattern: scala.util.matching.Regex = (\d{1,3}\.){3}\d{1,3}
scala> val str="my ip is 192.168.1.81"
str: String = my ip is 192.168.1.81
scala> println(pattern findAllIn str toList)
warning: there was one feature warning; re-run with -feature for details
List(192.168.1.81)
scala> for(matchStr <- pattern.findAllIn(str)){
| println(matchStr)
| }
192.168.1.81
scala>
scala> import java.io.FileReader
import java.io.FileReader
scala> import java.io.FileNotFoundException
import java.io.FileNotFoundException
scala> import java.io.IOException
import java.io.IOException
scala> try{
| val file=new FileReader("input.txt")
| }catch{
| case ex: FileNotFoundException =>{
| println("Missing file exception")
| }
| case ex: IOException => {
| println("IO Exception")
| }
| }
Missing file exception
scala>
(1)类的定义
public 是 Scala 的缺省访问级别
scala> class Point(x1:Int,y1:Int){
| var x:Int=x1
| var y:Int=y1
|
| def move(dx:Int,dy:Int){
| x=x+dx;
| y=y+dy;
| }
| def print(){
| println("("+x+","+y+")")
| }
| }
defined class Point
scala> var p=new Point(10,20)
p: Point = Point@3e7f7cd2
scala> p.move(2,3)
scala> p.print()
(12,23)
scala> p.print
(12,23)
程序说明:
(2)辅助构造器
scala> class Point{
| var x:Int=0
| var y:Int=0
|
| def this(x:Int){
| this()
| this.x=x
| }
|
| def this(x:Int,y:Int){
| this(x)
| this.y=y
| }
| }
defined class Point
scala> val p1=new Point
p1: Point = Point@6f694dd2
scala> var p2=new Point(1)
p2: Point = Point@7437ec41
scala> var p3=new Point(1,2)
p3: Point = Point@630643f6
scala>
程序说明:
(3)单例对象
Scala比Java更面向对象,因为在Scala中不能拥有静态成员,Scala它使用单例对象。单例是一种只能有一个实例的对象。使用object关键字对象而不是class关键字创建单例。由于无法实例化单例对象,因此无法将参数传递给主构造函数。
object下的成员都是静态的,若有同名的class,这其作为它的伴生类。在object中一般可以为伴生类做一些初始化等操作
(4)伴生对象
在Java或C++中,通常会用到既有实例方法也有静态方法的类,在Scala中将静态成员分离出来,形成与类同名的伴生对象(companion object)。类和它的伴生对象必须定义在同一个源文件中。类被称为是这个单例对象的伴生类(companion class)。
例子如下,直接将伴生类和伴生对象定义在同一源文件中即可。
class Account {
val id = Account.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double){ balance += amount }
}
object Account { //伴生对象
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber}
}
在spark-shell模式下,要同时定义类和对象,必须用粘贴模式。键入:paste
,然后键入或粘贴类和对象的定义,最后一Ctrl+D
退出粘贴模式。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Account {
val id = Account.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double){ balance += amount }
}
object Account { //伴生对象
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber}
}
// Exiting paste mode, now interpreting.
defined class Account
defined object Account
scala>
注意:类和他的伴生对象可以相互访问私有成员,他们必须定义在同一个源文件中。
(5)独立对象
不与伴生类共享名称的单例对象称为独立对象。它可以用在很多地方,例如作为相关功能方法的工具类,或者定义Scala应用的入口点。
比如下面程序中的Demo就是独立对象,其中包含了main方法,类似与Java的主类中的main方法,是应用程序的入口。
import java.io._
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
}
}
object Demo {
def main(args: Array[String]) {
val point = new Point(10, 20)
printPoint
def printPoint{
println ("Point x location : " + point.x);
println ("Point y location : " + point.y);
}
}
}
将上述程序保存在源文件:Demo.scala 中,使用Scala命令编译和执行此程序。
(6)apply方法
前面我们通过语句var a1 = Array("QQ", "Baidu", "Google")
直接创建了数组,为什么不使用new呢,为什么不使用Array的构造器呢?类似的语句还很多,比如List("apples", "oranges", "pears")
。
这是因为Scala在伴生对象中定义了apply方法,该方法返回的是伴生类的对象。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Account private(val newID:Int, newBalance:Double){
private val id =newID;
private var balance=newBalance
}
object Account {
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber}
def apply(newBalance:Double)=new Account(newUniqueNumber(),newBalance)
}
val act=Account(1000.0)
// Exiting paste mode, now interpreting.
defined class Account
defined object Account
act: Account = Account@6eac71db
scala>
程序说明:
注意:Array(100)和new Array(1000)是不同的。Array(100)是调用了伴生对象的apply方法,100是一个元素的值;而new Array(1000)是调用了Array类的辅助构造器this(100),创建了100个null元素。
(1)默认引入的包
每个Scala程序默认从下面代码开始:
注意:java.lang包首先被引入;scala包的引入有些特殊,它允许覆盖之前的引入。比如scala.StringBuilder会覆盖java.lang.StringBuilder类;Predef对象也被引入, 它包含了很多实用方法。
1、重写一个非抽象方法必须使用override修饰符。
2、只有主构造函数才可以往基类的构造函数里写参数。
3、在子类中重写超类的抽象方法时,你不需要使用override关键字。
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
}
}
class Location(override val xc: Int, override val yc: Int,
val zc :Int) extends Point(xc, yc){
var z: Int = zc
def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
println ("z 的坐标点 : " + z);
}
}
val loc = new Location(10, 20, 15);
loc.move(10, 10, 5);
// Exiting paste mode, now interpreting.
x 的坐标点 : 20
y 的坐标点 : 30
z 的坐标点 : 20
defined class Point
defined class Location
loc: Location = Location@1179731c
scala>