Scala从入门开始03
1.面向对象:
1.1类的定义
// Stendent.scala
package cn._xjk.myobj
/*
* 类
* */
class Stendent {
val id = 666
var age: Int = _
// 伴生对象可以调用
private var fv: Double = 99.99
// 只能在 Stendent 内部使用
private[this] var pwd = "123456"
def getpwd(): String = {
pwd
}
}
/*
* 静态对象
* 伴生对象:跟类同名,并且在同一个文件中
* */
object Stendent{
def main(args: Array[String]): Unit = {
val s1 = new Stendent
val fv = s1.fv
println(fv)
// s1.pwd
}
}
// StudentTest.scala
package cn._xjk.myobj
object StudentTest {
def main(args: Array[String]): Unit = {
val s = new Stendent
println(s.id)
s.age = 1000
println(s.age)
print(s.getpwd())
}
}
1.2.构造器
- 构造器分为主构造器和辅助,辅助构造器是主构造器的拓展,辅助构造器第一行需要调主构造器。
- 主构造器
package cn._xjk.myobj
// 主构造器:与类交织在一起
class Person(val name:String,var age:Int) {
}
object Person {
def main(args: Array[String]): Unit = {
val p = new Person("xiaoming", 20)
// p.name = "James" // 不可修改,因为式val定义
p.age = 21 // 可以修改式var 定义
val age = p.age
val name = p.name
println(age)
println(name)
}
}
- 辅助构造器
package cn._xjk.myobj
class Animal {
var name: String = _
println(name)
var age:Int = _
println(age)
def this(name:String, age:Int) {
this()
this.name = name
this.age = age
}
}
object Animal {
def main(args: Array[String]): Unit = {
val a = new Animal("cat", 15)
println(a.age)
}
}
- 辅助构造器与主构造器结合
package cn._xjk.myobj
class People(val name:String, var age:Int) {
// 辅助构造器传递额外参数
var fv:Double = _
// 定义辅助构造器,补充主构造器功能
// 定义辅助构造器一定要用def关键字,并且名字只能叫this
def this(name:String, age:Int, fv:Double) {
// 辅助构造器的第一行一定得调用构造器
this(name,age)
this.fv = fv
}
// // 无参辅助构造器
// def this() {
// this()
// }
}
object People{
def main(args: Array[String]): Unit = {
val p = new People("Lucy", 33, 55.5)
println(p.fv)
}
}
-
由上面可以知道,为了让类更加灵活,参数一般定义在辅助构造器中,并定义多个辅助构造器,使类传入的参数多样化。
-
私有构造器
- 在主构造器参数列表前面加private 表示私有构造器,访问权限只能是伴生对象。
package cn._xjk.myobj
/*
* 在主构造器参数列表前面加private 表示私有构造器
* */
class Monkey private (val name:String) {
}
object Monkey {
def main(args: Array[String]): Unit = {
val m = new Monkey("sun wukong")
}
}
- 包权限访问
package cn._xjk.myobj
/*
* private[myobj] 表示在同一个myobj包下才可以调用
* */
private[myobj] class Pig {
}
1.3 scala中静态对象
-
用object修饰
-
静态对象:object中定义的方法是静态方法,变量也是静态的。
-
伴生对象:跟类同名,并且在同一个文件中,类和伴生对象之间可以相互访问私有的方法和属性。
-
单例对象:在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的。在scala直接创建就是单例
package cn._xjk.myobj object SessionFactory { def main(args: Array[String]): Unit = { // 创建一个SessionFactory, 单例 val f1 = SessionFactory// cn._xjk.myobj.SessionFactory$@28f67ac7 val f2 = SessionFactory// cn._xjk.myobj.SessionFactory$@28f67ac7 println(f1) println(f2) } }
-
伴生对象与类之间私有属性和方法,可以互相使用
package cn._xjk.myobj
class Cat {
private def hello(): Unit ={
println(Cat.gender)
}
}
object Cat {
// 伴生对象的私有方法类中也可以使用
private val gender = "male"
def main(args: Array[String]): Unit = {
val c = new Cat()
println(c.hello())
}
}
- 应用
1.存放工具方法和常量
2.高效共享单个不可变实例
3.单例模式
1.4apply方法
- 通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用
package cn._xjk.myobj
class ArrayDemo1 {
}
object ArrayDemo1 {
def apply(): Unit = {
println("ok")
}
def apply(x:Int):Int = {
x * x
}
def apply(y:Double):Double = {
y * y
}
def main(args: Array[String]): Unit = {
var arr = ArrayDemo1
println(arr)
// ArrayDemo1() 是简写其实是调用了ArrayDemo1.apply()
// ArrayDemo1()
// ArrayDemo1.apply()
// 传入参数,会根据参数个数与类型去调用相应的apply方法
val r = ArrayDemo1(10)
print(r) // 180
val r1 = ArrayDemo1(6.0)
println(r1)// 36.0
}
}
1.5应用程序对象
- Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。
package cn._xjk.myobj
// 通过继承App不用写main方法,直接运行。App类实现main方法
object AppDemo extends App {
print("hello world!")
}
1.6继承
- 一个类中既有未实现方法,又有实现方法就是一个抽象类
package cn._xjk.myobj.ext
abstract class Animals {
// 未实现的方法
def eat():Unit
// 实现的方法
def run():Unit = {
println("跑啊跑")
}
}
1.7多态
- 多态实现具备三个条件:子类继承父类,方法重写,父类引用指向子类对象或接口指向实现类。(多态与反射密不可分)
package cn._xjk.myobj.ext
class Dog extends Animals {
// ctrl+i 导入未实现方法
// 实现未实现方法
override def eat(): Unit = {
println("狗吃肉")
}
// ctrl+o 导入重写方法
override def run(): Unit = {
println("四个腿,疯狂跑")
}
}
// 伴生对象
object Dog {
def main(args: Array[String]): Unit = {
// 1.Dog 继承 Animals
// 2.方法重写
// 3.父类引用: 父类指向子类/接口指向实现类
val m: Animals = new Dog
m.run()
}
}
1.8类型检查与强转
*Scala* | *Java* |
---|---|
obj.isInstanceOf[C] | obj instanceof C |
obj.asInstanceOf[C] | (C)obj |
classOf[C] | C.class |
// 强转类型
val animal = m.asInstanceOf[Animals]
animal.run()
// 判断类型
val flag = m.isInstanceOf[Animals]
println(flag)
// 查看类的class
val cls = classOf[Dog]
println(cls)
1.9 trait
- Scala 的trait相当于Java的接口,即trait中可以由没有实现的方法,也可以由实现的方法。
// Fightable接口实现了fight
trait Fightable {
def fight(): Unit = {
println("打架")
}
}
// Flyable 接口定义了 fly 未实现
trait Flyable {
def fly():Unit
}
- 实现接口特性
class Dog extends Animals with Flyable with Fightable {
// ctrl+i 导入未实现方法
// 实现未实现方法
override def eat(): Unit = {
println("狗吃肉")
}
// ctrl+o 导入重写方法
override def run(): Unit = {
println("四个腿,疯狂跑")
}
override def fly(): Unit = {
println("蹦蹦跳跳")
}
override def fight(): Unit = {
println("用嘴咬人")
}
}
object Dog {
def main(args: Array[String]): Unit = {
// 1.Dog 继承 Animals
// 2.方法重写
// 3.父类引用: 父类指向子类/接口指向实现类
val m: Dog = new Dog
m.run()
m.fly()
m.fight()
}
}
- 一个类,无论是继承还是实现接口特性,第一个都是extends, 如果继承某个类,必须extends修饰,并在第一个
class Pig extends Flyable {
override def fly(): Unit = {
println("猪在飞")
}
}
- 接口特性可以在伴生对象添加, 但是类不可以动态添加:
package cn._xjk.myobj.ext
class Rabbit {
}
object Rabbit {
def main(args: Array[String]): Unit = {
// 伴生对象:动态实现接口
val r = new Rabbit with Flyable{
override def fly(): Unit = {
print("兔子在飞...")
}
}
r.fly()
// 已经实现接口,直接使用
val r2 = new Rabbit with Fightable
r2.fight()
}
}
1.11 模式匹配和样例类
-
Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句、类型检查等。
并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配
-
字符串匹配
package cn._xjk.cases
import scala.util.Random
object CaseDemo01 extends App {
val arr = Array("James", "Curry", "Kebe")
val name = arr(Random.nextInt(arr.length))
println(name)
name match {
case "James" => println("詹姆斯")
case "Kebe" => {
println("科比")
}
case _ => println("什么没有听清,再说一次")
}
}
- 数据类型匹配
package cn._xjk.cases
object CaseDemo02 extends App {
val arr = Array("hello", 1, 2.0, CaseDemo02, 2L)
val elem = arr(2)
elem match {
case x: Int => println(s"Int $x")
case y: Double if (y >= 0)=> println(s"Double $y")
case z: String => println(s"String $z")
case CaseDemo02 => {
println("case demo 2")
}
case _ => {
println("default")
}
}
}
- 集合添加:
scala> arr :+ 6
res7: List[Int] = List(2, 3, 4, 5, 6)
scala> 1 +: arr
res8: List[Int] = List(1, 2, 3, 4, 5)
scala> arr
res9: List[Int] = List(2, 3, 4, 5)
- 匹配元组和List
package cn._xjk.cases
object CaseDemo3 extends App {
val lst = List(0,5)
println(lst.head) // 0
println(lst.tail)// List(5)
// 匹配List
lst match {
case 0 :: Nil => println("only 0")
case x :: y :: Nil => println(s"x $x y $y") // x 0 y 5
case 0 :: a => println(s"0 ... $a")
case _ => println("something else")
}
// 匹配元组
val tup = (1,3,7)
tup match {
case (1, x, y) => println(s"$x $y")// 3 7
case (_, z, 5) => println(z)
case _ => println("something else")
}
}
- 除了上述case匹配还可以对class和object匹配:
package cn._xjk.cases
import scala.util.Random
// case class 或 case object 效率更高
/*
* case class 可以不用new 已经实现序列化接口 主要用于模式匹配 多实例(每个实例都可以保存自己实例,有状态)
* case object 主要用于模式匹配 已经实现序列化接口 是单例的, 只要new一次即可
* */
case class SubmitTask(id:String, name:String)
case class HeartBeat(time:Long)
case object CheckTimeOutTask
object CaseDemo04 extends App {
val arr = Array(CheckTimeOutTask, new HeartBeat(1234), HeartBeat(888888), new SubmitTask("1", "James"))
val a = arr(Random.nextInt(arr.length))
a match {
case SubmitTask(id, name) => {
println(s"id $id name $name")
}
case HeartBeat(time) => {
println(time)
}
case CheckTimeOutTask => {
println("CheckTimeOutTask")
}
}
}
1.12 Option ,Some,None
-
在Scala中,从Map中取Key对应Value,返回是一个Option,根据key有可能取到对应value,也有可能取不到,取到了就是Some(v), Some中包装了对应的值,Some是多实例的,所以Some是一个case class。取不到就是None,None不用封装数据,None是单例的,不用封装数据。Some和None都继承了Option
-
示例1:
val map = Map("a" -> 1, "b" -> 2)
// b存在上面的map中,调用get获取Some(v),然后执行map方法
scala> map.get("b").map(_ *10)
res11: Option[Int] = Some(20)
// c不存在上面map中,调用get获取None,不执行后面map方法
scala> map.get("c").map(_ * 10)
res12: Option[Int] = None
- 示例2:
package cn._xjk.cases
object OptionDemo {
def main(args: Array[String]): Unit = {
val map = Map("a" -> 1, "b" -> 2)
var r = map.getOrElse("a", 0)
val o = map.get("b")
println(o)// None
val v = o match {
case Some(i) => {
i
}
case None => 0
}
println(v)// 0
}
}
1.13偏函数
- 被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配
- 类型是PartialFunction,由case没有match,主要功能是进行模式匹配。
package cn._xjk.cases
object PartialFuncDemo {
// 第一个参数传入值
// 第二个参数为返回值
def func1: PartialFunction[String, Int] = {
case "one" => {
println("one case")
1
}
case "two" => 2
case _ => -1
}
def func2(num:String):Int = num match {
case "one" => 1
case "two" => 2
case _ => -1
}
def main(args: Array[String]): Unit = {
print(func2("abc"))// -1
}
}