scala笔记
scala中object文件编译后对应java中的静态成员,非静态成员放在class文件中
1、变量
scala数据类型
char的值
var c1:Char = 'a' + 1 //类型不匹配
var c2:Char = 97 + 1 //类型不匹配
var c3:Char = 98 //对
var c4:Char = 999 //超范围
//分析:
//1.当把一个计算的结果复制给一个变量,编译器会进行类型转换和判断
//2.当把一个字面量赋给变量,编译器只会进行范围的判断
//3.(byte,short) 和 char之间不会自动转换
val c5:Byte = 5
val c6 = c4+c5 //c6为int
//4.byte short char 计算时先转换为int
2、方法
声明格式
def 函数名(参数1:参数类型,...): 返回值类型 = {
方法体
}
-
简写:
-
参数列表为空,若定义时省略
()
,则调用时也必须省略,否则可省可不省def fo(): Unit = { println("fo...")} fo() //fo... fo //fo... ======================= def fo: Unit = { println("fo...")} fo() //error fo //fo...
-
除以下3之情况外,
: 返回值类型
可省,函数返回值类型有编译器自动推断def fo(a: Int) = { println(s"a= $a")}
-
写
return
或使用递归函数时,返回值类型必须手动声明,编译器不会自动推断 -
如果省略
=
则始终返回Unit,不建议省略=
-
方法体只有一行,
{}
可以省
-
-
方法传入的形参其属性为val,不可重新赋值
-
方法可以有多个参数列表(柯里化),函数不可以
3、面向对象
主构造
class Dog(var name: String, val age: Int, sex: String) {
...
}
属性变量声明可以为var
、val
或无,scala编译后属性均以private
修饰
为var
时属性以private
修饰,scala编译后生成public的name()
和name_$eq(String name)
方法(即getter和setter);
为val
时属性以private final
修饰,scala编译后仅生成public的name()
方法;
无时,若主构造内部使用了该属性,则属性以private final
修饰同时生成private的name()
和name_$eq(String name)
方法;否则连属性都不生成。
抽象类
scala的抽象类关键字依然为abstract
,抽象类中依然可以有属性、代码块、抽象和非抽象方法,但scala中 abstract
不可修饰方法
trait(特质)
-
特质可类比为java中的接口,一个类可
with
混入(实现)多个特质,但其特点更像scala中的抽象类 -
scala中无
implements
关键字,实现使用extends
和with
关键字,实现多个特质时第一个用extends
,其后均用with
-
类的构造顺序:父类构造 --> 特质构造(先父特质后子特质)从左到右 --> 子类构造
继承
-
trait可以继承trait
-
trait可以继承class,如果trait A继承了class B,那么混入A的class C必须是B的子类
-
如果trait A指定了自身类型B,那么混入A的class C必须是B的子类
trait logger{ this:Exception => //指定自身类型为Exception def log()={ println(getMessage) } } class console extends Exception with logger{ //想要with logger则必须extends Exception }
覆写
-
java覆写父类字段,父类字段依然隐藏的存在,scala中覆写父类字段则该字段真的被覆盖,案例
-
val
可以覆写val
和没有()
的def
,var
只能覆写abstract var
隐式函数隐式类
-
增加现有函数的功能,如参数为A类型,返回值为B类型的函数
-
scala会自己去寻找符合输入输出的隐式函数,而不关心函数的内容,所以一个作用域里的隐式函数的输入输出不能完全相同
implicit def douhle2Int(num:Double): Int = num.toInt val a: Int = 10.1 println(a) //10
-
隐式类是隐式函数的升级版,隐式类只能是内部类而且主构造只能接受一个参数
-
隐式参数和隐式值:
- 一个函数里只可以有一个隐式参数,且调用该函数时如果不传入该参数值,则该隐式参数所在的小括号必须舍去
- 隐式值应定义在使用隐式值之前
4、元组(Tuple)
元组的主要用处:使方法返回多个值(类型可以不一样)
//创建元组的两种方法
val a1: (Int, String) = Tuple2(1, "hello") //最多为Tuple22
val a2: (Int, String) = (1,"hello")
访问元组元素
val b = a1._2 //"hello"
Tuple2也被称为对偶
5、数组(Array)
-
数组可分为定长数组(Array)和变长数组(ArrayBuffer,严格来讲属于collection)
-
创建Array对象
val a1: Array[Int] = new Array[Int](10) val a2: Array[Nothing] = new Array(10) //若不指定泛型则为Nothing val a3: Array[Array[Int]] = Array.ofDim[Int](3, 2) //生成2*3的二维数组 for(i <- 0 until a3.length ; j <- 0 until a3(i).length) a3(i)(j) = j for(i <- 0 until a3.length) println(a3(i).mkString(",")) //调用a3(i)每一个元素的toString,元素间以","间隔后拼接
-
数组的常用操作方法
:
的说明//:影响符号的结合方向,贴近:的是调用该方法的对象 //*符号的结合方向: + - * /等为左边对象调用的方法 //!a 中!则为右边对象a调用的方法
-
定长与变长共有
++ //连接两个数组 ++: //连接两个数组 :+ //一个数组连接一个元素,eg: arr1 :+ 10 +: //一个数组连接一个元素,eg: 10 :+ arr1 /: //左折叠 : //右折叠 head //第一个元素 tail //除第一个元素外的其他元素组成的数组 last //最后一个元素
-
变长独有
++= //将右数组的所有元素添加到左数组中 ++=: //将左...右... += //添加右元素至左数组中 +=: //..左...右... - //返回左数组去掉第一个右元素后的 新 数组 -- //返回左数组去掉右数组后的 新 数组 -= //左数组去掉第一个右元素 --= //左数组去掉右数组
-
经验小总结:
- 没有
=
参与的方法不改变原数组,只返回新数组 :
基本只改变方法的结合方向,不改变其作用
- 没有
-
6、容器(collection)
分为可变(mutable)容器和不可变(immutable)容器,对应包含所有数组的操作方法,对不可变容器进行增删操作将返回新的对象
-
总览
-
说明
-
scala.collection
包中的高级抽象类或triat -
scala.collection.immutable
包中的父子树 -
scala.collection.mutable
包中的父子树
-
创建容器对象
scala中不指明的情况时创建的Set、Map、Seq
都是Immutable
包下,为以示区分创建可变容器对象的推荐方式(set
为例)
import scala.collection.mutable
import scala.collection.immutable
object SetDemo {
def main(args: Array[String]): Unit = {
val set1: mutable.Set[Int] = mutable.Set(20, 50) //加上包名方便直接区分
val set2: Set[Int] = immutable.Set(20, 40)
println(set1) //Set(20, 50)
println(set2) //Set(20, 40)
}
}
List和ListBuffer
java中的List是接口,scala中List可以直接存放数据,默认情况下List不可变,ListBuffer为可变,ListBuffer比List少了以下的操作方法
- List的操作方法
//::
val list1 = List(10, 20, 30)
val list2 = List(100, 200)
println(list1 :: list2)//List(List(10, 20, 30), 100, 200)
println(10 :: list1)//List(10, 10, 20, 30)
println(list1)//List(10, 20, 30)
println(list2)//List(100, 200)
//即 :: 自右向左运算 为右边list对象调用,将左list或元素当成第一个元素放到右list的头部形成的新lsit返回
//:::
//自右向左运算 返回两个list拼接后的新list
println(Nil) //List(),Nil即为空list
// :: 、 ::: 不能与 +: 在同一式子中
list常用方法
集合(Set)
Set无序不重复,但immutable.Set
和mutable.Set
的内部排序机制并不相同
set常用方法
映射(Map)
Map存储k-v对,也可以认为存储的是对偶,Map
同样是无序不重复(key)
-
创建Map对象
val map1: Map[Int, String] = Map(1 -> "hello", 2 -> "scala") val map2: mutable.Map[Int, String] = mutable.Map((1, "hello"), (2, "world"))
-
Map获取和更新Value的方法
println(map1(1)) //hello println(map1(3)) //key not found: 3 println(map1.get(1)) //Some(hello) println(map1.get(3)) //None println(map1.getOrElse(1, "defaultValue")) //hello println(map1.getOrElse(3, "defaultValue")) //defaultValue println(map2.getOrElseUpdate(3, "scalaWorld")) //scalaWorld println(map2) //Map(2 -> world, 1 -> hello, 3 -> scalaWorld)
-
Scala Option(选项)类型用来表示一个值是可选的(有值或无值)。
Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None 。
-
map常用方法
其他
队列(queue)
FIFO 先进先出
val queue: mutable.Queue[Int] = mutable.Queue(20, 50)
queue.enqueue(30,70) //入队操作
println(queue) //Queue(20, 50, 30, 70)
queue.dequeue() //第一个元素出队
println(queue) //Queue(50, 30, 70)
immutable.Queue
很少使用,不变队列几乎没有价值,而且似乎无法使用enquequ()
、dequeue()
栈(Stack)
FILO 先进后出
val stack: mutable.Stack[Int] = mutable.Stack(40, 50, 70)
println(stack.pop()) //出栈 40
println(stack.push(90)) //入栈 Stack(90, 50, 70)
println(stack.push(1, 3)) //Stack(3, 1, 90, 50, 70)
并行容器
普通容器对象调用par方法可得到并行容器
//Demo
val parList: ParSeq[Int] = List(20, 30, 4).par
val parSet: ParSet[Int] = Set(20, 30, 4).par
val parArr: ParArray[Int] = Array(20, 30, 4).par
val parMap: ParMap[Int, String] = Map(1 -> "hello").par
parList.foreach(x => println(x +": "+ Thread.currentThread().getName))
//30: ForkJoinPool-1-worker-9
//20: ForkJoinPool-1-worker-13
//4: ForkJoinPool-1-worker-3
7、高阶算子(List、Set、Map可用)
演示用集合如下:
val list: List[Int] = List(2, 3, 5, 4, 1, 6)
val set: mutable.Set[Int] = mutable.Set(2, 3, 5, 4, 1, 6)
val map: immutable.Map[String, Int] = immutable.Map("hello" -> 1, "scala" -> 2, "why" -> 5, "you" -> 3, "soHard" -> 2)
foreach(遍历)
final def foreach(f: (A) ⇒ Unit): Unit
//f:为无返回值的函数
foreach
无返回值,它将调用方法的collection中每一个元素依次交给f函数处理
filter(一进至多一出)
def filter(p: (A) ⇒ Boolean): List[A] //以List举例
filter
返回值与调用方法的容器及容器泛型类型完全一致。容器中的每一个元素都被交给p函数处理,返回ture的才会被保留。
map(一进一出)
final def map[B](f: (A) ⇒ B): List[B] //通过遍历将容器中的元素转换为任意类型
map
返回值与调用方法的collection类型、元素数量都一致,但内部元素类型可以不同,其主要也用于类型转换,如:
val set: Set[Int] = Set(1, 2, 3)
println(set.map(x => List(x, x * x, x * x * x)))
//Set(List(1, 1, 1), List(2, 4, 8), List(3, 9, 27))
flatten
将容器中的容器元素拍平,甚至会将String拍成Char。返回值类型与调用方法的容器类型一致
val xs = List(
Set(1, 2, 3),
Set(1, 2, 3)
).flatten
// xs == List(1, 2, 3, 1, 2, 3)
val ys = Set(
List(1, 2, 3),
List(3, 2, 1)
).flatten
// ys == Set(1, 2, 3)
flatMap
等价于先map
再flatten
val list3 = List(1, 2, 3)
println(list3.flatMap(x => List(x, x * x, x * x * x)))
//List(1, 1, 1, 2, 4, 8, 3, 9, 27)
groupBy
def groupBy[K](f: (A) ⇒ K): Map[K, List[A]]
返回值类型为 Map[K, List[A]]
,以f函数的返回值K为分组依据,K为key、返回值K相同的元素组成的List[A]
为value,作为对偶放入返回的Map中
val list1 = List(3, 6, 5, 4, 13)
val list2 = List(3, 5, 13)
println(list1.groupBy(x => x % 2))
//Map(1 -> List(3, 5, 13), 0 -> List(6, 4))
println(list2.groupBy(x => x % 2))
//Map(1 -> List(3, 5, 13))
reduce(多进一出)
def reduce[A1 >: A](op: (A1, A1) ⇒ A1): A1
聚合,将调用reduce方法容器的头两个元素交给op函数处理,得到的返回值再和第三个元素一起被交给op函数,如此循环至最后一个元素,最终reduce的返回值必然与容器中元素的类型一致
foldLeft foldRight
def foldLeft[B](z: B)(op: (B, A) ⇒ B): B
聚合,方法的第一个参数列表只有一个参数z,z的类型为B,第二个参数列表为op函数,op函数接收两个参数(类型为B和容器元素类型A)。op对z和容器的第一个元素进行处理,返回类型为B的返回值,返回值再和容器的下一个元素一起被交给op函数,如此循环至最后一个元素,最终foldLeft的返回值必然为B类型。
foldRight方法与foldLeft 只在作用方向上不同,fold方法则较少使用
reduce和foldLeft方法的比较:
//举例:对于List[int],reduce后结果为int,而使用foldLeft若第一个参数列表给set[String]最终即可得到set[String]
val list = List(3, 6, 5, 4, 13)
println(list.reduce((x, y) => x + y))
//31
println(list.foldLeft(Set("hello"))((x, y) => x + y.toString))
//Set(4, 13, 5, 6, hello, 3)
scanLeft scanRight
scanLeft scanRight 和 foldLeft foldRight 机制相同,只不过scanLeft会将每次的结果都进行输出
val list = List(3, 6)
println(list.scanLeft(Set("hello"))((x, y) => x + y.toString))
//List(Set(hello), Set(hello, 3), Set(hello, 3, 6)...
排序
对象的可比性
java中要想实现类的不同对象间比较主要有两种,一种是类实现Comparable接口 覆写compareTo(),另一种是提供类的比较器Comparator。
//假如compareTo方法返回值为x,如果想要升序则This > Other时,x > 0
在scala中同样可以使用这两种方法。同时对于自定义类型A,scala中还可以通过以下方法实现比较:
-
混入Ordered[A]特质,覆写其中的compare()方法,使对象具有可比性
trait Ordered[A] extends scala.Any with java.lang.Comparable[A] { def compare(that : A) : scala.Int def <(that : A) : scala.Boolean = { /* compiled code */ } def >(that : A) : scala.Boolean = { /* compiled code */ } def <=(that : A) : scala.Boolean = { /* compiled code */ } def >=(that : A) : scala.Boolean = { /* compiled code */ } def compareTo(that : A) : scala.Int = { /* compiled code */ } }
-
提供Ordering[A]的实现类作为比较器,对两个对象进行比较
trait Ordering[A] extends java.lang.Object with java.util.Comparator[A] ...{ def compare(x : T, y : T) : scala.Int ... //Ordering已经提供了AnyVal、Option和Tuple2~Tuple9的隐式对象 }
-
总结:
Ordered
和Ordering
分别混入了Comparable
和Comparator
,他们相当于增强版,在原先的基础上提供了<
、>
等默认方法。
Seq的排序算子
scala的Seq类有三个算子,帮助实现Seq类内元素的排序
-
sorted()
def sorted[B >: A](implicit ord: math.Ordering[B]): List[A]
sorted
排序是稳定的,默认为升序,可使用sorted.reverse
降序,使用sorted
需要Seq中的元素具有前述的可比性,常见的用法之一是在调用方法前定义隐式值ord://Demo val user2s: List[User2] = List(new User2("bob2", 17), new User2("jack2", 15)) implicit val odr:Ordering[User2] = new Ordering[User2]{ override def compare(x: User2, y: User2): Int = x.age - y.age } println(user2s.sorted)
-
sortBy()
def sortBy[B](f: (A) ⇒ B)(implicit ord: math.Ordering[B]): List[A]
调用sortBy方法时:第一个参数列表是函数f(通常是匿名函数),f接收Seq元素类型A返回Ordering实现类型B;第二个参数列表是隐式参数,是Ordering的实现类。
val words = "The quick brown fox jumped over the lazy dog".split(" ") // this works because scala.Ordering will implicitly provide an Ordering[Tuple2[Int, Char]] //按照长度升序,首字母降序排序 words.sortBy(x => (x.length, x.head))(Ordering.Tuple2(Ordering.Int.reverse,Ordering.Char)) res0: Array[String] = Array(jumped, brown, quick, lazy, over, The, dog, fox, the)
-
sortWith()
def sortWith(lt: (A, A) ⇒ Boolean): List[A]
sortWith
排序是稳定的,调用sortWith
方法的时候仅需要传入函数lt,lt依次接收Seq里相邻的两元素,返回Boolean值。如果需要升序排序,则当前一个元素小于后一个元素时返回truescala> List("Steve", "Tom", "John", "Bob").sortWith(_.compareTo(_) < 0) res2: List[String] = List(Bob, John, Steve, Tom)
8、模式匹配
是对java
中的switch
的升级, 功能远远大于switch
-
模式匹配的时候, 如果匹配不到, 则会抛异常
-
匹配所有
case aa => // 可以使用匹配到值 case _ => // 用来兜底,匹配到的值用不了 本质一样(所有)!!!
-
关于匹配常量还是变量
case Baaaa => // Baaaa是常量 case baaaa => // baaaa新定义的变量
注意:
case
后面首字母是大写,表示常量, 首字母是小写表示变量
-
任何的语法结构都有值
模式匹配也有值. 值就是匹配成功的那个
case
的最后一行代码的值 -
匹配类型(简单)
val a: Any = 99 a match { // 只匹配[100,110]的整数. 守卫 case a: Int if a >= 100 && a <= 110 => println(a to 110) //指定b的自身类型为boolean case b: Boolean => println("是一个boolean: " + b) }//所有都匹配不上,报错
-
匹配类型(复杂)
在模式匹配中无法对除数组以外的其他容器的泛型做限制,案例
其原因是:scala的数组本质仍是java的数组,只是写法有变化,Array[Int]()、Array[Double]()本质仍是new int[0]、new double[0],本来就不是同一类型,故而可以限制;而其他容器由于泛型擦除(泛型出现的目的, 是为了在写代码的时候类型更安全,但是泛型只是出现在编译时, 编译成字节码之后, 泛型就不存在!),在运行时List[Double]()和List[Double]()并不能被识别出不同。
-
匹配内容
本质是匹配对象!!!
-
匹配数组的内容
-
匹配List的内容
-
匹配元组的内容
-
val arr = Array(10, 20, 100, 200, 300) arr match { /*case Array(a, b, c, d) => println(a) println(d)*/ /*case Array(10, a, b, c) => println(a)*/ /*case Array(10, a, _, 40) if a > 15 => println(a)*/ /*case Array(a, b, _*) => println(a) println(b)*/ case Array(a, b, rest@_*) => println(rest) }
- 匹配对象
解释清楚前面的内容匹配的原理
对象匹配的本质:
1. 是去调用这个对象的 unapply 方法, 把需要匹配的值传给这个方法
2. unapply方法, 返回值必须是 Option, 如果返回的Some,则表示匹配成功, 然后把
Some中封装的值赋值 case语句中
如果返回的是None, 表示匹配失败, 继续下一个case语句 -
9、 样例类
对象匹配, 必须要手动在伴生对象中去实现一个def unapply
方法.
样例他主要就是为模式匹配而生.
case class
其实就是scala
, 替我们实现很多方法, 这些方法大部分可以直接使用.
apply
unapply
hashCode
equals
...
case class User(age: Int, name:String)
1. 写在主构造中的属性默认都是val. 如果有需要可以改成var的
2. 默认实现了很多方法
apply
unapply
hashCode
equals
3. 使用场景
- 模式匹配
- 替代 java bean
- 作为进程间通信的通讯协议
10、偏函数
val list = List(10, "a", false, 20, 30)
// List(20, 40, 60)
// filter + map
val f: PartialFunction[Any, Double] = new PartialFunction[Any, Double] {
// 如果这个函数返回true, 则会对这个x进行处理(交给apply进行处理)
override def isDefinedAt(x: Any): Boolean = x match {
case _: Int => true
case _ => false
}
override def apply(v1: Any): Double = v1 match {
case a:Int => a * 2
}
}
val list2 = list.collect(f) // 等价于了 filter + map
println(list2)
定义方式2:
用一对大括号括起来的case
语句, 就是一个偏函数
{ case ...=>}
11、异常处理
java
中:
都是继承自Exception
特点: 代码会变的比较健壮
-
运行时异常
只有在运行的时候才有可能产生, 在源码中,可以处理, 也可以不处理
-
编译时异常(受检异常)
在源码的时候,必须处理.
IO, 网络
在scala
中, 所有的异常, 都可以处理, 也可以不处理.
用法:
-
处理
-
使用
try catch finally
-
抛出异常类型(
java: throws
scala: 注解
)@throws(classOf[RuntimeException]) @throws(classOf[IllegalArgumentException])
-
-
主动抛出
throw new IllegalArgumentException
scalac: 编译scala源码
scala: 进行运行
scala 源码.scala
当脚本用来(内部会先编译, 再运行)
12、泛型
符号 | 作用 |
---|---|
[T <: UpperBound] | 上界 |
[T >: LowerBound] | 下界 |
[T <% ViewBound] | 视界 |
[T : ContextBound] | 上下文界 |
[+T] | 协变 |
[-T] | 逆变 |
表格内容摘自:https://blog.csdn.net/datadev_sh/article/details/79854273
泛型的上限界定和下限界定
[T <: Ordered[T]] // 上限
[T >: Pet] // 下限. 推导的时候,不能和上限一样
三变
class MyList[T]
class Father
class Son extends Father
不变
MyList[Son] 和 MyList[Father] 没有任何的"父子关系"
错误: val fs: MyList[Father] = new MyList[Son]
默认情况下, 所有泛型都是不变的!!!
class MyList[T]
协变
val fs: MyList[Father] = new MyList[Son] // 正确的
class MyList[+T]
逆变
val fs: MyList[Son] = new MyList[Father] // 正确的
class MyList[-T]
scala中list和map的value已经使用了协变
上下文界定(泛型)
def max[T](x: T,y:T)(implicit ord: Ordering[T]) = {
if(ord.gt(x, y)) x
else y
}
[T:Ordering]
这就是泛型上下文.
表示: 一定有一个隐式值 Ordering[T] 类型的隐式值
上下文泛型的本质其实是对隐式参数和隐式值的封装!!!
视图界定
视图界定是对象隐式转换函数的封装!!!
def max[T <% Ordered[T]](x: T, y: T) :T = {
if(x > y) x
else y
}
/*def max[T](x: T, y: T)(implicit f: T => Ordered[T]) :T = {
if(x > y) x
else y
}*/
/*
1. 中置运算符
1 + 2
2. 一元运算符
后置
1 toString
前置
+5
-5
!false 取反
~2 按位取反
3. apply方法
任何对象都可以 调用
对象(...) // 对象.apply(...)
伴生对象
普通的对象
函数对象
4. update方法
user(0) = 100 // user.update(0, 100)
N-1、scala符号的使用
-
<-
- for循环中赋值
-
->
- map中key-value分隔符
-
=>
- 分割匿名函数及函数体
- 导包时对类重命名
-
-
-
1. 导包, 通配符 _ import java.util.Math._ 2. 屏蔽类 import java.util.{HashMap => _, _} 3. 给可变参数传值的时候, 展开 foo(arr:_*) 4. 元组元素访问 t._1 5. 函数参数的占位符 def compter(f:(Int) => Int) = f(3) println(computer((a: Int) => 2 * a)) //6 println(computer(2*_)) //与上一行等价 6. 方法转函数 val f = foo _ 7. 给属性设置默认值 class A{ var a: Int = _ // 给a赋值默认的0 } 8. 模式匹配的通配符 case _ => // 匹配所有 9. 模式匹配集合 Array(a, b, rest@_*) 10. 部分应用函数 math.pow(_, 2) 11. 在定义标识符的时候, 把字符和运算符隔开 val a_+ = 10 a+ // 错误 12. List[_] 泛型通配符 13. 自身类型 _: Exception =>
-
-
括号
scala
原生支持xml
, 标签都是用尖括号<user>
所以- 泛型使用
[]
- 访问数组或list的元素使用
()
- 泛型使用
N、较长的代码案例
类的构造顺序
trait A {
println("trait A的构造器....")
}
trait AA extends A {
println("trait AA的构造器....")
}
trait B {
println("trait B的构造器....")
}
trait BB extends B {
println("trait BB的构造器....")
}
class C {
println("class C的构造器....")
}
class CC1 extends C with AA with BB {
println("class CC1的构造器....")
}
class CC2 extends C {
println("class CC2的构造器....")
}
object Test {
def main(args: Array[String]): Unit = {
val cc1 = new CC1 //非动态混入
//class C的构造器....
//trait A的构造器....
//trait AA的构造器....
//trait B的构造器....
//trait BB的构造器....
//class CC1的构造器....
val cc2 = new CC2 with AA with BB //动态混入
//class C的构造器....
//class CC2的构造器....
//trait A的构造器....
//trait AA的构造器....
//trait B的构造器....
//trait BB的构造器....
}
}
java和scala的覆写区别
//java***
class Son extends Father{
int age = 10;
public int getAge(){
return this.age;
}
}
public class Father {
int age = 20;
public int getAge(){
return this.age;
}
public static void main(String[] args) {
Son s = new Son();
Father f = s;
System.out.println(f.age); //20
System.out.println(s.age); //10
System.out.println(f.getAge()); //10
System.out.println(s.getAge()); //10
}
}
//scala***
class Son extends Father {
override val age: Int = 10
override def getAge: Int = this.age
}
class Father {
val age: Int = 20
def getAge: Int = {
return this.age
}
}
object Father {
def main(args: Array[String]): Unit = {
val s: Son = new Son
val f: Father = s
System.out.println(f.age) //10
System.out.println(s.age) //10
System.out.println(f.getAge) //10
System.out.println(s.getAge) //10
}
}
对容器的泛型做模式匹配
def main(args: Array[String]): Unit = {
val a: Any = Array[Double](1.1, 2, 3)
val b: Any = List[Double](10.1, 20, 30)
val c: Any = Map(1->2)
// matchTest(a) 元素类型不一致,匹配报错
matchTest(b) //List[_]....
matchTest(c) //Map[_, _]...
}
def matchTest(a:Any): Unit = {
a match {
case a: Array[Int] =>
println("Array[Int]...")
case a: List[Int] =>
println("List[_]....")
case m: Map[Double, Boolean] =>
println("Map[_, _]...")
}
}