scala笔记

scala中object文件编译后对应java中的静态成员,非静态成员放在class文件中

1、变量

scala数据类型

Scala学习笔记-LMLPHP

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:参数类型,...): 返回值类型 = {
    方法体
  }
  • 简写:

    1. 参数列表为空,若定义时省略(),则调用时也必须省略,否则可省可不省

      def fo(): Unit = { println("fo...")}
      fo()	//fo...
      fo		//fo...
      =======================
      def fo: Unit = { println("fo...")}
      fo()	//error
      fo		//fo...
      
    2. 除以下3之情况外,: 返回值类型可省,函数返回值类型有编译器自动推断

      def fo(a: Int) = { println(s"a= $a")}
      
    3. return或使用递归函数时,返回值类型必须手动声明,编译器不会自动推断

    4. 如果省略=则始终返回Unit,不建议省略=

    5. 方法体只有一行,{}可以省

  • 方法传入的形参其属性为val,不可重新赋值

  • 方法可以有多个参数列表(柯里化),函数不可以

3、面向对象

主构造

class Dog(var name: String, val age: Int, sex: String) {
	...
}

属性变量声明可以为varval或无,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关键字,实现使用extendswith关键字,实现多个特质时第一个用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和没有()defvar只能覆写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也被称为对偶

tuple常用方法

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学习笔记-LMLPHP

    • scala.collection包中的高级抽象类或triat

      Scala学习笔记-LMLPHP

    • scala.collection.immutable包中的父子树

      Scala学习笔记-LMLPHP

    • scala.collection.mutable包中的父子树

      Scala学习笔记-LMLPHP

创建容器对象

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.Setmutable.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

​等价于先mapflatten

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的隐式对象
    }
    
  • 总结:

    OrderedOrdering分别混入了ComparableComparator,他们相当于增强版,在原先的基础上提供了 <>等默认方法。

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值。如果需要升序排序,则当前一个元素小于后一个元素时返回true

    scala> List("Steve", "Tom", "John", "Bob").sortWith(_.compareTo(_) < 0)
    res2: List[String] = List(Bob, John, Steve, Tom)
    

8、模式匹配

是对java中的switch的升级, 功能远远大于switch

  1. 模式匹配的时候, 如果匹配不到, 则会抛异常

  2. 匹配所有

    case aa =>
    	// 可以使用匹配到值
    
    case _ =>
    	// 用来兜底,匹配到的值用不了
    
    本质一样(所有)!!!
    
  3. 关于匹配常量还是变量

    case Baaaa =>  // Baaaa是常量
    case baaaa => // baaaa新定义的变量
    

注意:

  • case后面首字母是大写,表示常量, 首字母是小写表示变量
  1. 任何的语法结构都有值

    模式匹配也有值. 值就是匹配成功的那个case的最后一行代码的值

  2. 匹配类型(简单)

    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)
    }//所有都匹配不上,报错
    
    1. 匹配类型(复杂)

      ​在模式匹配中无法对除数组以外的其他容器的泛型做限制,案例

      ​其原因是:scala的数组本质仍是java的数组,只是写法有变化,Array[Int]()、Array[Double]()本质仍是new int[0]、new double[0],本来就不是同一类型,故而可以限制;而其他容器由于泛型擦除(泛型出现的目的, 是为了在写代码的时候类型更安全,但是泛型只是出现在编译时, 编译成字节码之后, 泛型就不存在!),在运行时List[Double]()和List[Double]()并不能被识别出不同。

    2. 匹配内容

      本质是匹配对象!!!

      • 匹配数组的内容

      • 匹配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. 匹配对象

    解释清楚前面的内容匹配的原理

    对象匹配的本质:
    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中, 所有的异常, 都可以处理, 也可以不处理.

用法:

  1. 处理

    • 使用try catch finally

    • 抛出异常类型(java: throws scala: 注解)

      @throws(classOf[RuntimeException])
      @throws(classOf[IllegalArgumentException])
      
  2. 主动抛出

    throw new IllegalArgumentException
    

    scalac: 编译scala源码

    scala: 进行运行


    scala 源码.scala

    当脚本用来(内部会先编译, 再运行)

12、泛型

表格内容摘自: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[_, _]...")
        }
    }

返回

05-26 08:20