Scala数据类型
下面列出的数据类型都是对象,也就是说scala没有Java中的原生类型。在scala是可以对数字等基础类型调用方法的。
数据类型 | 描述 |
---|---|
Byte | 8位有符号补码整数。数值区间为 -128 到 127 |
Short | 16位有符号补码整数。数值区间为 -32768 到 32767 |
Int | 32位有符号补码整数。数值区间为 -2147483648 到 2147483647 |
Long | 64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 |
Float | 32位IEEE754单精度浮点数 |
Double | 64位IEEE754单精度浮点数 |
Char | 16位无符号Unicode字符, 区间值为 U+0000 到 U+FFFF |
String | 字符序列 |
Boolean | true或false |
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null 或空引用 |
Nothing | Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 |
Any | Any是所有其他类的超类 |
AnyRef | AnyRef类是Scala里所有引用类(reference class)的基类 |
scala变量声明
变量定义语法
var|val filedName [: DataType] [= Initial Value]
在scala中变量类型是放在变量名之后等号之前的。
变量类型引用:
在Scala中声明变量和常量不一定要指明数据类型。在没有指明数据类型的情况下,其数据类型是通过变量或者常量的初始化值推断出来的。所以,如果在没有指明数据类型的情况下声明常量或变量必须要给出其初始值,否则将会报错。
var myVar = 10;
val myVal = "Hello, Scala!";
变量与常量
使用关键字"var"声明变量。
使用关键字"val"声明常量。
Scala多个变量声明
var xmax,ymax = 100 ; //xmax,ymax都声明为100。
scala访问修饰符
- scala中的访问修饰符有:private,protected,public
- scala默认访问修饰符是:public
- 较之Java,scala对protected的定义有更加限制。
- scala可以对可见性进行细粒度的控制。
scala的默认访问修饰符
如果没有修饰符,scala会默认把类、字段、方法的访问修饰符当做public。如果要改为private或protected,只需要在前面添加对应的修饰符关键字即可。就如下面的程序:
class Student {
def start() = println("started")
def stop() = println("stopped")
private def turnTable() = println("turning table")
}
// 调用
def main(args: Array[String]) {
var s = new Student
s.start()
s.turnTable; // 这里语法就过不去
}
protected修饰符
在scala里,用protected修饰的成员只对本类和子类可见,同一个包内的其他的类不可见。而且子类只可以访问本类实例的protected成员。可以通过一个例子看一下:
class Vehicle {
protected def checkEngine() = println("checked engine")
}
class Car extends Vehicle {
def start() {
checkEngine()
}
def tow(car: Car) {
car.checkEngine()
}
def tow(vehicle: Vehicle) {
vehicle.checkEngine() //不会报错
}
}
class GasStation {
def fillGas(vehicle: Vehicle) {
vehicle.checkEngine() //会报错
}
}
细粒度访问控制
一方面scala对待protected比Java更加严格,另一方面它提供了更多的灵活性和更细粒度的访问规则:
private和protected可以指定额外的参数。这样,就可以使用private[AccessQualifier],AccessQualifier可以是this,也可以是其它的类名或包名。这样就可以这么理解:这个成员对所有类都是private,除了自己和AccessQualifier所表示范围内的类。这个概念也是可以递推的,也就是说,如果AccessQualifier是一个类,那么private成员对于AccessQualifier的AccessQualifier也是可见的。
/**
* Created by robin on 2016/6/13.
*/
package society {
package professional {
class Executive {
private[professional] var workDetails = null
private[society] var friends = null
private[this] var secret = null
def help(another: Executive) {
println(another.workDetails)
println(this.secret)
println(another.secret) //会报错
}
}
}
package social {
class Acquaintance {
def socialize(person: professional.Executive) {
println(person.friends)
println(person.workDetails) //会报错
}
}
}
}
在类Executive的定义中,三个私有成员变量有着不同的作用范围。workDetails对包professional内的类可见,friends对society包内的类可见,而secret只对当前实例可见。
类定义以及对象创建
简单类的定义与对象创建
scala中类默认就是public的,且多个类可以包含在同一个源文件中:
class Counter{
private var value = 0//类成员变量必须初始化,否则报错
def increment(){ //类中的方法默认是公有可见性
value += 1
}
def current() = value //对于类中的“取值方法”,在定义时可省略掉括号,直接 def current = value
}
// 对象创建以及方法调用:
object TestMain {
def main(args: Array[String]): Unit = {
var counter = new Counter //或new Counter()
counter.increment();
println(counter.current().toString);
}
}
scala的类在未提供构造方法时,默认也会提供无参构造方法;且在调用无参构造器或无参方法时可省略掉方法后的括号。
类中无参方法的调用
调用无参方法比如current时,你可以写上圆括号,也可以不写:
myCounter.current //OK
myCounter.current() //同样OK
应该用哪一种形式呢,我们认为对于改变对象成员属性的方法使用(),而对于仅仅是读操作而不会改变对象状态的方法去掉()是不错的风格。
你也可以直接通过不带()的方法声明来强制使用不带()的调用风格:
class Counter {
def current=value // 定义了一个名为current的方法,方法体就是 return value
}
// 正确的调用
counter.current
// 错误的调用
counter.current()
属性的getter和setter方法
Scala类的每个类成员变量都有getter和setter方法,私有成员变量的getter和setter默认是私有的,公有成员变量的getter和setter方法默认是公有的。
假设类中有属性value,Scala类默认生成的getter方法名为value,默认生成的setter方法名为value_=。但是使用时,我们可以重新定义获取或设置属性的方法。
假设针对于下面的类定义:
class Person {
var age=0
}
调用getter和setter方法:
var person = new Person
person.age // 将调用Persion.age方法
person.age = 20 // 将调用fred.age=(21)
person.age_=(30)
printf(person.age.toString)
如果想亲眼看一下这些方法,可以使用javap反编译查看字节码内容:
F:\myworkspace\spark\target\classes\com\boothsun> javap -private Person.class
Compiled from "Counter.scala"
public class com.boothsun.Person {
private int age;
public int age();
public void age_$eq(int);
public com.boothsun.Person();
}
构造器
scala的类可以有一个主构造器和多个辅助构造器。每个辅助构造器的方法名称为this,每个辅助构造器都必须调用已经定义的辅助构造器或主构造器开始定义。
主构造器:
如果一个类没有显示定义主构造器,则有一个默认的无参主构造器(比如之前定义的类)。
带有主构造器的类定义 示例:
class Student(val name:String, var age:Int = 0, address:String = "", private var school:String = ""){
var grade:Int = if( age>7 ) age-7 else 0
println(" I'm in main constructor. ")
def info() = " name is "+name+", age is "+age+", address is "+address
}
对于Scala类,主构造器的参数放置在类名后,由括号括起来。且对于主构造器中var、val、private等标注的参数,都会成为类的对应字段,并生成对应的默认getter、setter方法。如Student类中的name、age、school等。对于主构造器中的未用var、val标注的参数,如果在类的任何一个方法用用到该参数,该参数将会转换为类的字段,否则不会,如Student类的address属性。
由于在Student类中的info方法中用到了参数address,所以Student共有name、age、address、school、grade等5个属性,且Scala根据对应属性的特点生成了默认的getter和setter方法。
对于主构造器的参数,也可以提供参数默认值。通过为主构造器提供默认值可减少辅助构造器的个数。
主构造器的函数体,是类中除了方法定义以外的其他语句,如在Student类的主构造器中,包含grade属性的初始化和prinln这两行语句。主构造器会执行类定义中的所有语句。
var student = new Student("boothsun",111) //后面address、school参数使用默认值
student.age