Scala号称跟Java很相似,但实际上,差别颇大
Scala拥有很多简化语法,使用灵活多变,从另一个角度理解,就是不适合新人
1. 静态的差别
- Scala没有静态成员(变量,方法,类),没有static关键字
- Scala用单例对象(object)实现静态功能
Scala单例对象(object)和类(class)同名且同时存在于一个.scala源文件中时,称为伴生,伴生的对象和类可以互相访问对方的私有成员
名词术语: 伴生(companion) 一个类的伴生对象(companion object) 单例对象的伴生类(companion class)
定义单例对象(object)不等于定义类(class)<-Scala抽象概念
- 单例对象不带参数,类可以带参数
- 单例对象通过synthetic class的一个实例来实现
- 单例对象在第一次访问的时候初始化
一个互相调用的例子,可以看出来伴生的特点:
object 伴生互相访问测试 {
def main(args: Array[String]): Unit = {
Demo.of
new Demo().cf
}
}
object Demo {
// 单例对象调用它的伴生类的方法
def of {
var d = new Demo
//这里调用一下伴生类class的私有方法
d.f(3)
//更可以直接调用伴生类的私有变量
println(d.id)
//可以修改伴生类的私有变量
d.id += 1
println(d.id)
}
private var id: Int = 22138;
private def f(i: Int): Unit = {
println("object的方法,i=" + i)
}
}
class Demo {
private var id: Int = 12138;
private def f(i: Int) {
println("class的方法,i=" + i)
}
//类调用伴生对象的私有变量和方法
def cf {
Demo.f(Demo.id)
}
}
运行结果:
class的方法,i=3
12138
12139
object的方法,i=22138
2. apply和update
原帖链接,作者万岁:http://1025250620.iteye.com/blog/1827423
Scala作为一种脚本语言,添加了一些约定以增加编程的灵活性,比如:
println(10)
// 指定方法调用者时,可以省略点和括号
Console println 10
apply的约定:
用括号传递给变量(对象)一个或多个参数时,Scala 会把它转换成对 apply 方法的调用
例子:
1.theArray(0), 取数组的第一个元素的操作会转换成 theArray.apply(0) 操作,这也能解释为什么 Scala 数组取值不用中括号括下标的方式,因为它也是一次方法调用
2.anyObject(“key1”) 会被转换成 anyObject.apply(“key”) 操作,这也会让我们想到 Map 的取值操作,的确如此。我们可以举个例子:
object apply测试 {
def main(args: Array[String]): Unit = {
var sc = new SomeClass
//注意这里的调用方式,println(实例化的对象(参数)),类似于数组(0)
println(sc("12138"))
}
}
class SomeClass{
def apply(key : String ): String = {
println("调用apply方法,key=" + key)
"Hello apply"
}
}
测试结果
调用apply方法,key=12138
Hello apply
3.数组Array,键值对Map的构造,比较如下代码
//数组Array
var array = Array(1, 2, 3)
//完整代码
var array1 = Array.apply(4, 5, 6)
//键值对Map
var map = Map("A" -> 65, "B" -> 66)
//完整代码
var map1 = Map.apply("C" -> 67, "D" -> 68)
我们在看一个单例对象object的例子
object EMail {
// 这种定义并没有特殊用途,只能作为普通方法调用
def apply: Unit = {
println("一个没有参数的apply方法")
}
def apply(account: String, domain: String): String = {
println("带参数的apply方法")
account + "@" + domain
}
def main(args: Array[String]): Unit = {
// 不含参数的调用,无法自动调用apply方法
println(EMail)
// 运行结果:
// 面向对象测试.EMail$@1b40d5f0
println(EMail("simplelife12138","163.com"))
// 运行结果:
// 带参数的apply方法
// simplelife12138@163.com
}
}
update的约定:
1. 当对带有括号并包括一到若干参数的进行赋值时,编译器将使用对象的 update 方法对括号里的参数和等号右边的对象执行调用
2. 元组Tuple没有update
比如:
var array3 = Array("goodbye", "my", "love")
// Array类型没有办法自动输出内容,直接输出的是内存地址,
// 这里使用toList将Array转化为List来显示
println(array3.toList)
array3(0) = "hello"
//array3.update(0, "hello")
println(array3.toList)
运行结果:
List(goodbye, my, love)
List(hello, my, love)
3. 元组Tuple
元组并不仅仅只是数组Array,也可以是键值对Map,如下示例
// 省略Array的数组是元组,Tuple类型
//var array2 = Array(1, 2, 3)
var array2 = (1, 2, 3)
println(array2.getClass)
// 省略Map的键值对也是元组,Tuple类型
var map2 = Map("a" -> 97, "b" -> 98)
var map2 = ("a" -> 97, "b" -> 98)
println(map2.getClass)
运行结果:
class scala.Tuple3
class scala.Tuple2