1. 类
1.1 简单的类
T1.scala
object T1 {
// 定义一个类
class Counter{
private var value=0
def increment():Unit={value+=1}
// def increment()=value+=1
// def increment(){value+=1}
def current():Int={value}
}
def main(args: Array[String]): Unit ={
var c = new Counter
// var c = new Counter()
c.increment()
c.increment()
println(c.current())
// 对于无参方法,可以省略()
println(c.current)
}
}
1.2 编译&执行
T2.scala
class Counter{
private var value=0
def increment(step){value+=step}
def current():Int={value}
}
val c = new Counter
c.increment(5)
println(c.current())
可以直接执行
scala T2.scala
输出: 5
对于含有object 的文件,有时需要先编译成.calss字节码文件,在shell环境下运行:
scalac T1.scala
会自动生成 T1.class和T1$Counter.class两个文件。
然后再运行即可:
scala T1.scala
1.3 getter和setter方法
class Counter{
private var myvalue=0
// getter()
def value = myvalue
// setter()
def value_=(new_value:Int) ={
if(new_value>0)
myvalue = new_value
}
def increment(step:Int):Unit={myvalue+=step}
def current():Int={myvalue}
}
object MyCounter {
def main(args: Array[String]): Unit ={
var c = new Counter()
println(c.value)
c.value = 3
c.increment(5)
println(c.current)
}
}
// 0, 8
1.4 构造器
scala 构造器包含1个主构造器和若干个(0或多个)辅助构造器,其中辅助构造器的名字为this,且每个辅助构造器都必须调用一个此前已经定义的辅助构造器或主构造器。
1.4.1 辅助构造器
class Counter{
private var myvalue = 0
private var name = ""
private var mode = 1
def this(name: String){
this() // 调用主构造器
this.name = name
}
def this(name: String, mode: Int){
this(name) // 调用前一个辅助构造器
this.mode = mode
}
def increment(step: Int):Unit = {myvalue += step}
def current():Int = {myvalue}
def info():Unit = {
printf("Name:%s and mode is %d\n", name, mode)
}
}
object MyCounter {
def main(args: Array[String]): Unit ={
var c = new Counter("kk", 3)
c.increment(5)
println(c.current)
c.info
}
}
1.4.2 主构造器
Scala的主构造器与Java不同,它的主构造器是整个类体,需要在类名称后面罗列出构造器所需的所有参数,这些参数被编译成字段,且字段的值就是创建对象时传入的参数的值。
class Counter(val name: String, val mode: Int){
private var myvalue = 0
def increment(step: Int):Unit = {myvalue += step}
def current():Int = {myvalue}
def info():Unit = {
printf("Name:%s and mode is %d\n", name, mode)
}
}
object MyCounter {
def main(args: Array[String]): Unit ={
var c = new Counter("kk", 3)
c.increment(5)
println(c.current)
c.info
}
}
// Name:kk and mode is 3
2. 对象
2.1 单例对象
Scala采样object关键字实现单例对象,提供静态方法和静态字段。
test.scala
object Person {
private var id = 0
def new_person_id()= {
id += 1
id
}
}
printf("The first person id is %d.\n", Person.new_person_id())
printf("The second person id is %d.\n", Person.new_person_id())
printf("The third person id is %d.\n", Person.new_person_id())
//The first person id is 1.
//The second person id is 2.
//The third person id is 3.
不能编译,可直接执行 scala test.scala
2.2 伴生对象
当单例对象与某个类具有相同的名称时,这个单例对象被称为这个类的“伴生对象”,(这个类被称为这个单例对象的“伴生类”),伴生对象可以同时提供实例方法和静态方法。要求类和它的伴生对象必须存在于同一个文件中,而且可以相互访问私有成员(字段和方法)。
class Person {
private val id = Person.new_person_id()
private var name = ""
def this(name: String){
this()
this.name = name
}
def info(): Unit ={
printf("The id of %s is %d.\n", name, id)
}
}
object Person {
private var id = 0
def new_person_id()= {
id += 1
id
}
def main(args: Array[String]): Unit ={
val p1 = new Person("k1")
val p2 = new Person("k2")
p1.info()
p2.info()
}
}
//The id of k1 is 1.
//The id of k2 is 2.
Scala源代码编译后都会变成JVM字节码,此时class与object在Java层面会被合二为一,其中class里面的成员成了实例成员,object成员成了static成员。
2.3 应用程序对象
test.scala
object HelloWorld {
def main(args: Array[String]): Unit ={
println("Hello World!!!")
}
}
执行:
1. 直接执行
scala test.scala
2. 先编译再执行
scalac test.scala
scala -classpath . HelloWorld
2.4 apply()与update()
2.4.1 apply()
用括号传递给变量(对象,包括单例对象)一个或多个参数时,Scala会把它转换成对apply()的调用。
class Test {
def apply(param: String): String = {
println("apply() called! parameter is: " + param)
"Hello, world"
}
}
val obj = new Test
println(obj("kk"))
//apply() called! parameter is: kk
//Hello, world
用 scala test.scala 执行
单例对象亦是
object Test {
def apply(param: String): String = {
println("apply() called! parameter is: " + param)
"Hello, world"
}
}
val obj = Test("k1")
// apply() called! parameter is: k1
println("-------------")
println(obj)
// Hello, world
伴生类和伴生对象情况:
class Test {}
class ApplyTest{
def apply() = println("apply() called!")
def greeting: Unit = {println("greeting() called!")}
}
object ApplyTest{
def apply() = {
println("apply() called! ---object---")
new ApplyTest()
}
}
object Test{
def main(args: Array[String]): Unit = {
val a = ApplyTest() // 调用伴生对象中的apply(),因为没有new
// apply() called! ---object---
a() // 调用伴生类中的apply()
// apply() called!
a.greeting
// greeting() called!
}
}
执行 val a = ApplyTest()时,会导致apply()的调用并返回该方法调用的值,即ApplyTest的实例化对象。当执行a()时,又会导致调用伴生类的apply(),如果我们需要,就可以在伴生类的apply()中写入一些处理逻辑,这样就可以把传入的参数赋值给实例化对象的变量。
比如:
val arr = Array("11","22","33")
此处没有使用new关键字,不用构造器,直接给对象传递3个参数,这时Scala就会调用Array类的伴生对象Array的apply(),完成数组的初始化。
2.4.1 update()
当对带有括号并包括一到若干参数的对象进行赋值时,编译器将调用对象的update(),并把括号里的参数和等号右边的对象一起作为update()的输入参数来执行调用。
object Test{
def main(args: Array[String]): Unit = {
val arr = new Array[String](3) // 数组中的每个元素初始化为null
arr(0) = "11" // 调用了伴生类Array中的update(),执行 arr.update(0,"11")
arr(1) = "22"
}
}
可以看出在进行元组赋值时,之所以没有采用Java中的[]而是采用()的形式arr(0),是因为存在上述的update()的机制。
3. 继承
与Java不同点:
1. 在子类中重写超类的抽象方法时,不需使用override关键字;
2. 重写一个非抽象方法,必须使用override修饰符;
3. 只有主构造器可以调用超类的主构造器;
4. 可以重写超类中的字段。
abstract class Car { // 抽象类不能直接被实例化
val brand: String // 抽象字段,没有初始值
def info() // 抽象方法,不需使用abstract 修饰
def greeting() {
println("Welcome to my car!")
}
}
class BMWCar extends Car {
override val brand: String = "BMW"
def info() {
printf("This is a %s car!\n", brand)
}
override def greeting() {
println("Welcome to BMW car!")
}
}
class BYDCar extends Car {
override val brand: String = "BYD"
override def info() {
printf("This is a %s car!\n", brand)
}
override def greeting() {
println("Welcome to BYD car!")
}
}
object MyCar {
def main(args: Array[String]): Unit ={
val c1 = new BMWCar()
val c2 = new BYDCar()
c1.info()
c1.greeting()
c2.info()
c2.greeting()
}
}
4. 特质(trait)
trait不仅实现了接口的功能,还具备很多其他的特性,可以同时拥有抽象方法和非抽象方法。
在Scala中,一个类只能继承自一个超类,却可以实现多个特质,从而重用特质中的方法和字段,实现多继承。
trait CarId {
var id: Int
def currentId(): Int // 抽象方法,没有方法体
}
class BMWCar extends CarId { // 继承特质,也可使用with
override var id: Int = 10
def currentId(): Int = {id += 1; id}
}
class BYDCar extends CarId {
override var id: Int = 20
def currentId(): Int = {id += 1; id}
}
object MyCar {
def main(args: Array[String]): Unit ={
val c1 = new BMWCar()
val c2 = new BYDCar()
println(c1.currentId())
println(c2.currentId())
}
}
多继承
trait CarId {
var id: Int
def currentId(): Int // 抽象方法,没有方法体
}
trait CarGreeting {
def greeting(msg: String){println(msg)}
}
class BMWCar extends CarId with CarGreeting {
override var id: Int = 10
def currentId(): Int = {id += 1; id}
}
class BYDCar extends CarId with CarGreeting {
override var id: Int = 20
def currentId(): Int = {id += 1; id}
}
object MyCar {
def main(args: Array[String]): Unit ={
val c1 = new BMWCar()
val c2 = new BYDCar()
c1.greeting("BMW")
println(c1.currentId())
c2.greeting("BYD")
println(c2.currentId())
}
}