Scala学习笔记2——面向对象
程序员文章站
2022-06-14 22:10:01
...
Scala学习笔记2——面向对象
-
实例
class Person { var name : String = _ //占位符,暂不初始化 val age = 10 private[this] val gender = "male" //private[this]表示gender只能内部使用 } object Basic { def main(args : Array[String]) { val p = new Person //类的构造函数没有参数时可以不写括号 p.name = "Jack" println(p.name + ": " + p.age) } }
-
类
-
声明类:一个源文件中可以包含很多类,并且都是public级别。
-
getter 和 setter
- 使用var声明会自动生成set和get方法,使用val声明只会自动生成get方法。
- 当不需要任何get和set方法,可以声明为private[this]
- 如果字段是private,则自动生成的setter和getter也是private的,需要自己写set,get方法。
-
构造函数 :主构造器/附属构造器
//1.主构造器直接跟在类名后面,主构造器中的参数会被编译成字段 //2.主构造器执行的时候,会执行类中的所有语句 //3.如果参数声明时不带(val/var),则相当于private[this],外部没法访问 class Person(val name : String, val age : Int){ println("primary constructor") var gender : String = _ //附属构造器一定是this命名,首行一定要调用已经存在的构造器 def this(name : String, age : Int, gender : String){ this(name,age) this.gender = gender } } def main(args : Array[String]){ //主 val p = new Person("Jack",20) println(p.name+":"+p.age) //附 val p = new Person("Jack",20, "male") println(p.name+":"+p.gender) }
-
继承
class Person(val name : String, val age : Int){ println("primary constructor") var gender : String = _ val school = "buaa" def this(name : String, age : Int, gender : String){ this(name,age) this.gender = gender } } //父类已有的字段就不用使用val或var修饰了 Class Student(name : String, age : Int, val major : String) extends Person(name, age){ println("subclass,major :"+major) //重写父类方法 override def toString = "Override toString" override val school = "BUAA" } def main(args : Array[String]){ //先调用父类的主构造器,再调用子类的主构造器 val s = new Student("Justin",30,"Math") println(s.toString) }
-
-
抽象类:
- 类的一个或多个方法没有完整的定义
- 声明抽象方法的时候不需要加abstract关键字,只需要不写方法体(当然类名需要abstract关键字修饰)。
- 子类重写父类抽象方法(字段)时不需要加override。
- 父类可以声明抽象字段(无初始值的字段)
abstract class Person1{ def speak val name : String var age : Int } class Student1 extends Person1{ def speak { println("speak") } val name = "AAA" var age = 100 } object Basic3 extends App{ val s = new Student1 s.speak }
-
特质(trait)——对比JAVA8接口
- 包含字段,有方法体的方法,抽象方法
- 通过with关键字,一个类可以扩展多个特质
trait Logger{ /* def log(msg : String) { println("log" + msg) } */ def log(msg : String) } trait ConsoleLogger extends Logger{ //trait的子特性重写抽象方法不需要override def log(msg : String) { println(msg) } } //没有extends,不能有with class Test extends Logger{ def test{ log("xxx") } } object Basic3 extends App{ val t = new Test t.test //输出logxxx } ///////////////////////////////// trait ConsoleLogger{ def log(msg : String) { println("save"+msg) } } trait MessageLogger extends ConsoleLogger{ //继承非抽象方法需要override override def log(msg : String){ println("save to bank"+ msg) } } abstract class Account{ def save } class MyAccount extends Account with ConsoleLogger{ def save{ log("100") } } object Basic4 extends App{ val acc = new MyAccount acc.save //若想对对象混入特质,如下操作 val acc = new MyAccount with MessageLogger//(可以看成细化了trait) acc.save //会调用对象上的特质 }
附:蛋糕模式
-
蛋糕模式的思路是:假如A依赖B,我们用一个特质把被依赖方B包裹起来,我们可以叫它BComp,再用一个特质把依赖A方包裹起来,我们可以叫它AComp,我们会把AComp的自身类型声明为BComp, 这样我们可以在AComp中*引用BComp的所有成员,这样从形式上就实现了把B注入到A的效果。
-
此外,两个Comp都要有一个抽象的val字段来代表将来被实例化出来的A或B。最后就是粘合各个组件,这需要第三个类,它同时继承Acomp和Bcomp,然后重写Comp里要求的val字段,来实例化A和B,这样,一切就都粘合并实例化好了。
-
实例
trait EngineComponent { trait Engine { private var running = false def start(): Unit = { /* as before */ } def stop(): Unit = {/* as before */ } def isRunning: Boolean = running def fuelType: FuelType } protected val engine : Engine protected class DieselEngine extends Engine { override val fuelType = FuelType.Diesel } } trait CarComponent { this: EngineComponent => // gives access to engine trait Car { def drive(): Unit def park(): Unit } protected val car: Car protected class HondaCar extends Car { override def drive() { engine.start() println("Vroom vroom") } override def park() { … } } } //tie them all together object App extends CarComponent with EngineComponent with FuelTankComponent with GearboxComponent { override protected val engine = new DieselEngine() override protected val fuelTank = new FuelTank(capacity = 60) override protected val gearBox = new FiveGearBox() override val car = new HondaCar() } App.car.drive() App.car.park()
-
Apply 与 单例
class ApplyTest { def apply() = "Apply" def test{ println("test") } } //object中的方法默认为静态方法(scala中没有static关键字) //本身就是单例 object ApplyTest{ def apply() = new ApplyTest //静态变量与静态方法 var count = 0 def incr = { count = count + 1 } } class Basic4{ } object Basic4 extends App{ val a = ApplyTest()//类名加括号就已经调用了apply方法 //类名不加括号会创建对象并运行object中不属于任何方法的句子 val t = new ApplyTest println(t())//对象加括号调用的是class中的apply方法 }
-
包 package com.xx.data
-
支持嵌套,下层可以访问上层作用域中的名称
//play框架 package.com.chinahadoop{ package spark{ // } }
-
顶部标记(不同包不能互相访问)
package com.a package b
-
包对象
可以把一些公用的东西定义在包里面。
-
包可见性
可以在package里面定义哪些可见哪些不可见
-
包在任何地方都可以引入,作用域至该语句所在块的末尾
{ import xx.xxx.xyy }
-
重命名引入成员
import java.util.(HashMap => JavaHashMap)
-
隐藏方法
HashMap => _
-
自动引入
java.lang._
package aa.bb.cc.dd class XXX{ private[dd] def spark = {} //则spark只能被dd包下的文件引用 }
-
-
模式匹配
-
标准用法(match)
//extends App相当于main函数 object Basic5 extends App{ val value = 1 //scala中匹配成功后立刻退出,不需要手动break val result = value match { case 1 => "one"//match的返回值 case 2 => "two" case _ => "other" } val result2 = value match { case i if i==1 => "one" } def t(obj : Any) = obj match { case x : Int => "Int" case s : String => "String" case _ => "other" } }
-
-
Case class(多用于模式匹配中)
- 构造器中的每一个类型都为val
- 不用new就可以直接产生对象(因为有apply方法)
object CaseClassDemo extends App{ def m(p : Person){ p match{ //也可以带名字匹配,例如case Teacher("ab"),只能匹配名字为ab的teacher对象 case Teacher(_) => println("teacher") case Student(_) => println("student") case _ => println("unknown") } } m(Teacher("A")) } abstract class Person case class Teacher(name : String) extends Person case class Student(name : String) extends Person
-
文件读取
import scala.io.Source object FileDemo extends App{ val file = Source.fromFile("/User/char.data") //读取网站上的内容: source.println("http://www.baidu.com") //按行打印 for(line <- file.getLines()){ println(line) } //按字符打印,两个println会打印两行 for(ch <- file){ println(ch) } }
-
Option
- Some(): 代表有确定值
- None:没有确定值
val m = Map(1->2) m.get(10) match { case Some(v) => println(v) case None => println("No such Key") }
-
String Interpolation
s"hello" val b = "world" s"hello $b"//返回hello world
-
两个推荐的原码:
Spark中的RDD.scala, SparkContext.scala