scala学习笔记

scala语言:完全面向对象的语言(学习笔记)

hello world

object Hello {
  def main(args: Array[String]): Unit = {
    println("Hello World!")
  }
}


def:声明
Unit:返回值(java中的void)
//scala源码中包含了main方法,在编译后自动形成了public static void main
//scala在编译源码时,会生成两个字节码文件,静态main方法执行另外一个字节码文件中的成员main方法
//scala是完全面向对象的语言,那么没有静态的语法,只能通过 模拟 生成静态方法
//编译时将当前类生成一个特殊的类==>、、、、、、   然后创建对象来调用这个对象的main方法

//一般情况下,将加$类的对象,称之为伴生对象
//伴生对象中的内容,都可以通过类名访问,来模拟java中的静态语法
//伴生对象的语法规则,使用object

//public static void main(String[]arrays){方法体}
//scala中没有public关键字,默认所有的访问权限都是公共的

//scala中没有void关键字,采用特殊的对象来模拟void

//scala中声明方法采用关键字def
//方法后面的小括号是方法的参数列表
//scala中参数列表的声明和java不一样

//java:String 参数名
//scala:  参数名:类型

//java中方法的声明和方法体直接连接
//scala中方法的声明和方法体通过=连接
//scala中将方法的返回值类型放置在方法声明的后面使用冒号连接
image-20210405173448657

scala注意事项:

1、scala源文件以scala为扩展名

2、scala程序的执行入口是main()函数

3、scala严格区分大小写

4、scala方法由一条条语句构成,每个语句后不需要分号(scala语言会在每行后自动加分号),体现出scala的简洁性

5、如果在同一行有多条语句,除了最后一条语句不需要分号,其他语句需要分号。

package scala.chapter1
//打印字符串
object scala_02 {
  def main(args: Array[String]): Unit = {
    //变量
    val name="加藤惠"
    val age=17;
    val url="先有圣人后有天,吾惠美如画中仙"

    //打印字符串
    println("测试打印")
    //字符串通过+号连接(类似java)
    println("name="+name+" age="+age+" url="+url)
    //print用法(类似C语言)字符串通过%传递。(格式化输出)
    printf("name=%s,age=%d,url=%s \n",name,age,url)
    //字符串插值,通过$引用(类似PHP)
    println(s"name=$name,age=${age},url=$url")
    //保留2位小数
    println(f"name=$name,age=${age}%.2f,url=$url")
  }
}

//val修饰的对象引用可以改变,val修饰的则不可以改变,但对象的状态(值)却是可以改变的(比如:自定义对象、数组、集合等等)

//Scala与Java有着相同的数据类型,在Scala中数据类型都是对象,也就是说scala没有java中的原生(基本)类型

//地址不能变,但内容可变

package scala_chapter2

object scala_02 {
  def main(args: Array[String]): Unit = {
    //能省则省
    //scala为了让开发过程变得简单,可以将自动推断出来的内容省略
    val username:String ="gafafa"
    val name="list"
    //声明变量时,类型可以省略(这就是类型判断)
    //类型确定后,就不能修改,说明scala是强类型语言
    //3.在声明/定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改
    //val修饰的对象属性在变异后,等同于加上final
    //val修饰的对象引用可以改变,val修饰的则不可以改变,但对象的状态(值)却是可以改变的(比如:自定义对象、数组、集合等等)
    //变量声明时,必须有初始值(显示初始化)

    val dog=new Dog()//地址不能变,但内容可变
    dog.name="ell";
    println(dog.name)
  }
}
class Dog{
  var name:String=""
}

//Scala与Java有着相同的数据类型,在Scala中数据类型都是对象,也就是说scala没有java中的原生(基本)类型
/*
scala数据类型分为两大类AnyVal(值类型)和AnyRef(引用类型)
注意:不管是AnaVal还是AnyRef都是对象
 */

//相对于java的类型系统,scala要复杂谢谢,也正是这复杂多变的类型系统才让面向对象编程和函数式编程完美融合在一起


package scala_chapter2

object scala_datatype {
  def main(args: Array[String]): Unit = {
    //数据类型


    //scala是完全面向对象的语言,所以没有基本数据类型
    val age:Int=20
    //byte,short,int long float double char boolean
    val b:Byte=10;
    val s:Short=10;
    val i:Int=10;
    val f :Float=10;
    val d:Double=10;
    val bln:Boolean=true;
    val c:Char='c';
    val ii:Integer=10
    //scala中10这个数字也是一个对象,可以调用方法

  }
}

整型的使用细节

1、scala各整数类型有固定的表数范围和字段长度,不受具体OS的影响,以保证Scala程序的可移植性

2.scala的整型 常量/字面量 默认为int型,声明为Long型 常量/字面量 虚后加‘I’或‘L’

3.scala程序中变量常声明为int型除非不足以表示大数,才使用Long

字符类型(char)

基本介绍

字符类型可以表时单个字符,字符类型是Char,16位无符号Unicode字符(2个字节),区间值为U+0000到U+FFFF

var c1:Char='a'
var c2:Char='\t'
var c3:Char='你'
var c4:Char=97

boolean类型

1.布尔类型也叫Boolean类型,Boolean类型数据只允许取值true和false

2.Boolean类型占一个字节

3.Boolean类型适于逻辑运算,一般用于程序流程控制:

if条件控制语句

while循环控制语句

do-while循环控制语句

for循环控制语句

三个空类型

注意:null只能赋值给引用类型,不能给值类型

强制类型转换

int i=(int)2.5

scala: var num:Int =2.7.toInt//面向对象

强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级

+,-号没有byte和short之间的操作

标识符概念:

1.Scala对各种变量、方法、函数等命名时使用的字符序列称为标识符

2.凡是自己可以起名字的地方都叫标识符

标识符的命名规则

Scala中的标识符声明,基本和java是一致的,但是细节上会有所变化

1.首字符为字母,后续字符任意字母和数字,美元符号,可后接下划线

2.数字不可以开头

3.首字符为操作符(比如+ - * /),后续字符也需跟操作符,至少一个

val ++ ="123"可行 在class中为 plusplus

val %#$=true 可行

val +a+=“123” 不可行

4.操作符(比作±*/)不能在标识符中间和最后

5.用反导号(飘号)‘…’包括的任意字符串,即使关键字(39个)也可以

val ‘private’:String="123"可行

scala中可以使用特殊符号作为标识符,其实是将特殊符号在编译时进行了转换

scala中下划线有特殊的用途,不能独立当做变量名来使用(java中可以)

val Int =“123” 可行

运算符

1.算术运算符

算术运算符的运算规则和java一样

Scala中没有++、–操作符,需要通过+=、-=来实现同样的效果

2.赋值运算符(同java)

3.比较运算符

如果两个浮点数进行比较,应当保证数据类型一致.

4.逻辑运算符

5.位运算符

Scala不支持三目运算符 , 在Scala 中使用 if – else 的方式实现。

运算符描述实例
&按位与运算符(a & b) 输出结果 12 ,二进制解释: 0000 1100
|按位或运算符(a | b) 输出结果 61 ,二进制解释: 0011 1101
^按位异或运算符(a ^ b) 输出结果 49 ,二进制解释: 0011 0001
~按位取反运算符(~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。
<<左移动运算符a << 2 输出结果 240 ,二进制解释: 1111 0000
>>右移动运算符a >> 2 输出结果 15 ,二进制解释: 0000 1111
>>>无符号右移A >>>2 输出结果 15, 二进制解释: 0000 1111
类别运算符关联性
1() []左到右
2! ~右到左
3* / %左到右
4+ -左到右
5>> >>> <<左到右
6> >= < <=左到右
7== !=左到右
8&左到右
9^左到右
10|左到右
11&&左到右
12||左到右
13= += -= *= /= %= >>= <<= &= ^= |=右到左
14,左到右

键盘输入语句

在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取。InputDemo.scala

java:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-saeDxVn8-1618126542281)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406081620354.png)]

scala:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d6zc2oAW-1618126542283)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406081635513.png)]

scala核心编程

程序控制流

在scala中没有switch,而是使用模式匹配来处理。

范围数据循环方式1
基本案例
for(i <- 1 to 3){
print(i + " ")
}
println()
说明
i 表示循环的变量, <- 规定好 to 规定
i 将会从 1-3 循环, 前后闭合 (包括1 和 3)

for(i <- 1 until 3) {
print(i + " ")
}
println()
说明:
这种方式和前面的区别在于 i 是从1 到 (3-1)
前闭合后开的范围,和java的arr.length() 类似
for (int i =0; i < arr.lenght(); i++ ){}

for(i <- 1 to 3 if i != 2) {
print(i + " ")
}
println()

基本案例说明
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为true则进入循环体内部,为false则跳过,类似于continue

引入变量

for(i <- 1 to 3; j = 4 - i) {
print(j + " ")
}

对基本案例说明
没有关键字,所以范围后一定要加;来隔断逻辑

上面的代码等价

for (i <- 1 to 3) {
var j = 4 – i
print(j + “ “)
}

for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j)
}

对基本案例说明
没有关键字,所以范围后一定要加;来隔断逻辑
上面的代码等价

for(i <- 1 to 3){

​ for(i <- 1 to 3){

​ println(“ok”)

}

}

val res = for(i <- 1 to 10) yield i * 2
println(res)

输出结果:Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

对基本案例说明
将遍历过程中处理的结果返回到一个新Vector集合中,使用yield关键字

Scala内置控制结构特地去掉了break和continue,是为了更好的适应函数化编程,推荐使用函数式的风格解决break和contine的功能,而不是一个关键字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hWfDH7rg-1618126542285)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406085506400.png)]

函数式编程

基础

1.函数定义/声明

2.函数运行机制

3.递归

4.过程

5.惰性函数和异常

高级

1.值函数(函数字面量)

2.闭包

3.应用函数

4.抽象控制…

在scala中,函数式编程和面向对象编程融合在一起,学习函数式编程式需要oop的知识,同样学习oop需要函数式编程的基础。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mUY91sxy-1618126542287)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406091314897.png)]

1.在scala中,方法函数几乎可以等同(比如他们的定义、使用、运行机制都是一样的),只是函数的使用方式更加的灵活多样

2.函数式编程是从编程方式(范式)的角度来谈的,可以这样理解:函数式编程把函数当成一等公民,充分利用函数、支持的函数的多种使用方式。

比如:

在scala中,函数式一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量,函数的创建不用依赖于类或者对象,而在java当中,函数的创建要依赖于类、抽象类或者接口

3.面向对象编程是以对象为基础的编程方式

4.在scala中函数式编程和面向对象编程融合在一起了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xvuv8HPr-1618126542289)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406091938031.png)]

函数式编程介绍:

函数式编程是一种“编程范式”(programming paradigm)

它属于“结构化编程”的一种,主要思想是吧运算过程尽量写成一系列嵌套的函数调动。

函数式编程中,将函数也当做数据类型,因此可以接受函数当做输入(参数)和输出(返回值)。(增强了编程的粒度)

函数式编程中,最重要的就是函数。

def 函数名 ([参数名: 参数类型], …)[[: 返回值类型] =] {
语句… //完成某个功能
return 返回值
}
1.函数声明关键字为def (definition)
2.[参数名: 参数类型], …:表示函数的输入(就是参数列表), 可以没有。 如果有,多个参数使用逗号间隔
3.函数中的语句:表示为了实现某一功能代码块
4.函数可以有返回值,也可以没有
5.返回值形式1: // def 函数名(参数列表) : 数据类型 = {函数体} // 返回值确定,清晰
6.返回值形式2: // def 函数名(参数列表) = {函数体} // 有返回值, 类型是推断出来的
7.返回值形式3: // def 函数名(参数列表) {函数体} // 无返回值 Unit
8.如果没有return ,默认以执行到最后一行的结果作为返回值

函数递归需要遵守的原则(总结):

1.程序执行一个函数时,就创建一个新的受保护的独立空间(新函数栈桢)

2.函数的局部变量是独立的,不会相互影响

3.递归必须向退出递归的条件逼近,否则就是无线递归

4,当一个函数执行完毕,或者遇到return,就会返回,遵守谁调用,就将结果返回给谁

函数的形参列表可以是多个, 如果函数没有形参,调用时 可以不带()

形参列表和返回值的数据类型可以是值类型和引用类型。

Scala中的函数可以根据函数体最后一行代码自行推断函数返回值类型。那么在这种情况下,return关键字可以省略

def getSum(n1: Int, n2: Int): Int = {
n1 + n2
}

def getSum(n1: Int, n2: Int) = {
n1 + n2
}

因为Scala可以自行推断,所以在省略return关键字的场合,返回值类型也可以省略

如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,这时要明确写成 : 返回类型 = ,当然如果你什么都不写,即使有return 返回值为()

如果函数明确声明无返回值(声明Unit),那么函数体中即使使用return关键字也不会有返回值

如果明确函数无返回值或不确定返回值类型,那么返回值类型可以省略(或声明为Any)

def f3(s: String) = {
if(s.length >= 3)
s + “123”
else
3
}

def f4(s: String): Any = {
if(s.length >= 3)
s + “123”
else
3
}

Scala语法中任何的语法结构都可以嵌套其他语法结构(灵活),即:函数/方法中可以再声明/定义函数/方法,类中可以再声明类。

Scala函数的形参,在声明参数时,直接赋初始值(默认值),这时调用函数时,如果没有指定实参,则会使用默认值。如果指定了实参,则实参会覆盖默认值

如果存在多个参数,每一个参数都可以设定默认值,那么这个时候,传递的参数到底是覆盖默认值,还是赋值给没有默认值的参数,就不确定了(默认按照声明顺序[从左到右])。在这种情况下,可以采用带名参数

def mysqlCon(url:String = “jdbc:mysql://localhost",
port : Int = 3306,
user: String = “root”,
pwd : String = “root”): Unit = {
println(“host=" + host)
println(“port=” + port)
println(“user=” + user)
println(“pwd=” + pwd)
}

def f6 ( p1: String = “v1”, p2: String ) {
println(p1 + p2);
}
f6(“v2” ) 不行
f6(p2=“v2”) 不行

scala支持可变参数

说明:
args 是集合, 通过 for循环 可以访问到各个值。

可变参数需要写在形参列表的最后。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3LJbBBZ8-1618126542290)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210406102409298.png)]

传值调用和传名调用

var money = 100
def buy(): Int = {

​ money -= 10

​ money

}

def test1(a: Int) = {

​ println(a)

​ println(a)

}

def test2(a: => Int) = {

​ println(a)

​ println(a)

}

def main(args: Array[String]): Unit = {

​ test1(buy)
​ test2(buy)
}

高阶函数

将其他函数作为参数或返回值为一个函数的函数函数(higher-order function)

// 函数的第一个参数类型是另一个函数
def apply(f: Int => String, v: Int) = f(v)

def fmtInt(n: Int) : String = “[整数值{” + n + “}]”

def main(args: Array[String]): Unit = {

println(apply(fmtInt, 1200))

}

 //scala可以采用自动推动功能来简化函数的声明
    /*
    1.如果函数声明时,明确无返回值,,那么即使函数体中有return也没用


     */
//    def test(): Unit ={
//      return "张三"
//    }
//    println(test())

    //如果将函数体的最后一行打码进行返回,那么return关键字可以省略

    //如果明确函数没有返回值,那么等号可以省略,省略后,编译器不会酱函数体最后一行代码作为返回值
    //如果函数没有参数列表,可以省略小括号,调用时不能加小括号
    //如果函数没有参数列表,但没有省略小括号,调用时可加可不加

    //匿名函数
    ()->(println("bbbbbb"))
//函数式编程
    //可变参数
    def test(name:String*): Unit ={
      println(name)
    }
test("1","2","3")
    //默认参数
    def test1(name:String,age:Int=20): Unit ={
      println(s"${name} - ${age}")
    }
    test1("zhangsan")
    test1("杭三",30)
    //调用函数时,从前到后,从左到右

函数在scala中可以做任何事情

函数可以赋值给变量

函数可以作为函数的参数

函数可以作为函数的返回值

def f(): Unit ={
  println("fff")
}

def f0()={
  //返回一个函数
  //直接返回函数,但不执行,需要增加特殊符号:_
  f _
}

f0()()//将函数作为参数返回
def f1(i:Int)={
  def f2(j:Int): Int ={
    //println("f2f2f2f2")
    i*j
  }
  f2 _
}


println(f1(10)(20))



//函数柯里化(闭包)
    //一个函数在实现逻辑时,将外部的变量引入到函数的内容,改变了这个变量的生命周期,称之为闭包
    def f3(i:Int)(j:Int):Int={
        i*j
    }

    println(f3(10)(20))



//将函数作为参数传递给另外一个参数,需要采用特殊的声明方式
    //()=>Unit
    //参数列表=>返回值类型
        def f4(f :()=>Int): Int ={
      f()+10
    }

    def f5():Int={
      5
    }
    println(f4(f5))

补充:

栈上分配

逃逸分析

def f7(f:(Int)=>Unit): Unit ={
  f(10)
}
    def f8(i:Int): Unit ={
      println(i)
    }
    f7(f8)
def f7(f:(Int)=>Unit): Unit ={
  f(10)
}
    f7((i)=>{println(i)})

惰性(延迟加载)

object test_lazy {
  def main(args: Array[String]): Unit = {
    lazy val res=sum(10,20)+"是结果"
    println("___________")
    println("____________")
    println("______________")
    println("______________")

    println(res)
  }
  def sum(a:Int,b:Int): Int ={
    println("执行了")
    a+b
  }


}

面向对象编程

//面向对象
//TODO scala是一个完全面向对象的语言
//scala中的包的声明方式默认和java是一致的,但是有其他的使用方式
//1)在同一个源码文件,可以多次声明
//声明的类在最后的那个包中
//源码中的类所在的位置不需要和包的路径相同
//2)scala中所有的语法都可以进行嵌套
//  package可以使用小括号,小括号内部生命的类在这个包中,之外声明的类不在这个包中
//3)scala中可以声明父包和子包,父包中的类,子类可以直接访问,不需要引入,其实就是作用域的概念
//4)scala中package可以声明类。但是无法声明变量和函数(方法)
//5)为了弥补包的不足,使用了包对象的概念
//包对象中可以声明属性和方法
//


object test_01 {
  def main(args: Array[String]): Unit = {
    var user:User=new User()

    user.username="zhangsan"
    println(user.username)


  }
}
//声明类
class User{
  //声明属性
  var username:String=_

  var age:Int = _

  //方法
  def login():Boolean={
    true
  }
}
/*
import用于导入类
import可以在任何地方使用
import可以导入一盒包中所有的类,采用_代替*
import导入相同包中的多个类,采用大括号进行包含处理

 */

import java.util.{ArrayList,List,Date}


//scala中如果想要从最开始的包中查找类,需要增加绝对路径,使用_root_开头



[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wDHkueWu-1618126542290)(D:\scala\030_Scala\4.视频\调用问题.jpg)]

在类中声明属性,默认为是私有的,但是底层提供了公共的setter和getter方法,所以可以正常调用

如果给属性增加private修饰符,那么属性无法在外部访问,因为底层神生成的setter和getter方法都是私有的。

如果声明的属性使用val,那么属性是私有的,底层只提供getter方法,没有setter方法

为了和java的bean规范统一,scala提供了注释,生成java中对应的set,get方法

伴生对象(静态)可以访问伴生类(成员)的私有属性

创建伴生类对象,需要提供特殊的方法,实现相应的功能

scala自动识别apply方法,用于创建伴生类对象

val student=Student(“zhangsan”)

println(student)

构造方法

函数和类中 = 在确定没有任何返回值的情况下可以省略

package scala_chapter06

object scala_son {
  def main(args: Array[String]): Unit = {
    //TODO 创建对象
    val user=new User09("路人女主")
    print(user)
  }
}
//TODO scala的构造方法分为2类:主构造方法和辅助构造方法
/*
scala构建对象可以通过辅助构造方法创建,但是必须调用主构造方法
scala是完全面向函数的语言,所以类也是函数
类是一种函数,可以使用小括号作为函数的参数列表
类所代表的函数其实就是这个类的构造方法
默认情况下,scala也是给类提供无参构造方法
在类的后面声明的构造方法就是主构造方法
 */
class User09(s:String) {
  //TODO 类体 & 构造方法体
  println(s)

  //声明辅助构造方法,方法名为this
  def this(){
    this("wangwu")
  }
  
}
类的继承和抽象类


package scala_chapter06

object scala_class {
  def main(args: Array[String]): Unit = {
//    val user=new User10()
//    user.name
    val uset=new User10
    uset.test()

  }
}
//声明类
/*
父类,继承
类可以声明为抽象的 abstract

 */
abstract class Person{
    var name:String= _

  //声明抽象方法,方法只有声明没有实现,不需要abstract声明
  def test()
}

class User10 extends Person {
  //重写抽象方法,补全方法
  override def test(): Unit = {
    print("路人女主")

  }
}

动态绑定



package scala_chapter06

object scala_dump {
  def main(args: Array[String]): Unit = {
    val user=new User11
    user.test1()
  }
}
abstract class Person{
  //scala找那个属性也可以重写,因为属性可以抽象
  var name:String =_
  //不完整,为抽象属性
  //TODO 属性只有声明,而没有初始化,那么就是抽象属性
  //抽象属性在编译为class文件时,不产生属性,但是产生抽象的getter方法
  var sex:String
  //声明抽象方法,方法只有声明,没有实现,不需要abstract
  def test()

  def test1():Unit={

  }
}
class User11 extends Person{

  override def test(): Unit = {

    print("路人女主")
  }
  //TODO scala如果子类重写父类的方法(不是抽象),需要增加override关键字
  override def test1(): Unit ={
    print("clannad")
  }


  //属性可以被覆盖(重写),但是不能重写父类var声明的变量
  override var sex: String = _
}
package scala_chapter06

object scala_lei_con {
  def main(args: Array[String]): Unit = {
    val user=new User13("123")

    println(user.s)
  }
}
//类构造方法的参数的作用域默认为整个类的主体,但是如果想要参数作为属性来使用,可以采用特殊方式声明
class User13(var s:String){
  
}

特质

package scala_chapter06
/*
接口
scala中没有接口的概念没有interface,但是有特质
trait,类似于接口
 */

object scala_jieko {
  def main(args: Array[String]): Unit = {
    val user=new User14
    print(user)
  }
}
//声明特质
trait Testtrait{
}

trait Testtrait1{
}
class Person14{
}
//特质可以继承,所以使用extend关键字
//如果类继承多个特质,采用with连接
//如果类同时存在父类和特质,依然采用继承方式,但是继承的是父类,连接特质
class User14 extends Testtrait with Testtrait1 {

}
package scala_chapter06

object TEST_scala_trait {
  def main(args: Array[String]): Unit = {
    //java中的接口无法直接构建对象
    //scala中的特质也无法构建对象
    /*
    scala中的特质可以执行代码
    scala特质中声明的属性和方法都可以在混入的类中调用
     */

    val user=new User15()
    user.test()
  }
}
trait TestTrait15{
    //println("jkjkjkjkjk")
//  var username:String="jkjkjkjk"
//
//  def test(): Unit ={
//    println("沙优")
//  }
  //特质中可以声明抽象方法
  def test()


}

class Person15{

}

class User15 extends Person15 with TestTrait15{
  override def test(): Unit = {
    println("111111")

  }
}
package scala_chapter06

//TODO  特质和父类没有关系,只和当前混入的类有关,所以,在调用时,父类先执行,然后混入当前的特质再执行,然后当前类再执行
//如果父类混入了相同特质,那么该特质的代码只会执行一遍


object scala_con_con {
  def main(args: Array[String]): Unit = {
    val user=new User__2
  }
}

trait user_000{
  println("trait code")
}
class User_1{
  println("paresen _code")
}

class User__2 extends User_1 with user_000 {
  println("child code")
}
object scala_con_con {
  def main(args: Array[String]): Unit = {
    val ttt=new test_000
    ttt.insert()
  }
}

trait  Operate{
  println("Operate...")

  def insert(): Unit ={
    println("插入数据")
  }
}


trait MySql extends Operate{
  println("Mysql...")

  override def insert(): Unit ={
    println("向数据库")
    super.insert()
  }
}
//特质可以继承其他特质
//特质可以重载父特质的方法
trait File extends Operate{
  println("File...")

  override def insert(): Unit ={
    println("向文件中")
    super.insert()
  }
}
//多特质混入时代码执行顺序为从左到右,如果有父特质,会优先执行
//多特质混入时,方法的调用为从右到左
//特质中super的关键字指代上一级,而不是父特质


class test_000 extends MySql with File{

}
/*
执行结果

Operate...
Mysql...
File...
向文件中
向数据库
插入数据



 */

隐式转换

package scala_chapter07

object scala01_Transform {
  def main(args: Array[String]): Unit = {
    /*
   自动转换-隐式转换
   scala默认的情况下支持数值类型的自动转换
   byte->short->int -> long
   scala默认的情况下支持多态语法中的类型自动转换
   child ->parent->trait(interface)
   scala也允许开发人员自定义类型转换规则
   将两个无关的类型通过编程手段让他们可以自动转换
    */
    implicit def transfrom(d:Double):Int={
    d.toInt
    }

    //OCP
    val i:Int=5.0

    print(i)

  }
}

OHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH!!!

package scala_chapter07

object Scala02_Transform1 {
  def main(args: Array[String]): Unit = {
    implicit def transform(mysql:Mysql):Operater={
      new Operater
    }
    var mysql=new Mysql
    mysql.select()
    mysql.delete()
  }
}

class Operater{
  def delete(): Unit ={

  }
}

class Mysql{
  def select(): Unit ={

  }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ErSc7yJa-1618126542291)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409073811830.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TgSxNH7u-1618126542292)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409073919560.png)]

object Scala03_Transform2 {
  def main(args: Array[String]): Unit = {

    def test(implicit  name:String="加藤惠"): Unit ={
      println("Hello"+name)
    }

    test

  }
}
object Scala03_Transform2 {
  def main(args: Array[String]): Unit = {

    //隐式值
    implicit val username:String ="路人女主"
    //隐式参数
    def test(implicit  name:String="加藤惠"): Unit ={
      println("Hello"+name)
    }
    test
  }
}



输出结果:Hello 路人女主
object Scala03_Transform2 {
  def main(args: Array[String]): Unit = {

    //隐式值
    implicit val username:String ="路人女主"
    //隐式参数
    def test(implicit  name:String="加藤惠"): Unit ={
      println("Hello"+name)
    }
    //test
    test()
  }
}

输出结果:hello加藤惠
package scala_chapter07

object Scala04_Transform3 {
  def main(args: Array[String]): Unit = {
    val user4=new User4

    user4.insert()
    user4.delete()
  }


  class User4{

    def insert(): Unit ={

    }

  }
  
  implicit class Person4(u:User4){
    def delete(): Unit ={
      
    }
  }


}

隐式类使用的特点:

1.其所带的构造参数有且只能有一个

2.隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的

3.隐式类不能是case class

4.作用域内不能有相同名称的标识符

隐式的转换时机

1.当方法中的参数的类型与目标类型不一致时(二次编译)

2.当对象调用所在类中不存在的方法或成员时,编译器会自动将对象进行隐式转换(根据类型)

package scala_chapter07

import scala_chapter07.Scala04_Transform3.User4

object Scala04_Transform3 {
  def main(args: Array[String]): Unit = {
    val user4=new User4

    user4.insert()
    user4.delete()
  }
  class User4 extends Test {
    def insert(): Unit ={

    }
  }

}
trait Test {

}
//创建一个伴生对象
object Test{
  implicit class Person4(u:User4){
    def delete(): Unit ={

    }
  }
}

数组

object Scala02_Array {
  def main(args: Array[String]): Unit = {
    //scala中的数组,使用array对象实现,声明使用中括号声明数组的类型
    //Array[String]
    //scala可以使用简单的方式创建数组
    //Array可以通过apply方法来创建数组对象
    val ints = Array(1, 2, 3, 4)
    //访问数组:使用小括号,增加索引的方式来访问数组
    println(ints(0))//1
    //数组长度
    println(ints.length)//4
    println(ints)//[I@28f67ac7
    //将数组转化为字符串打印出来

    println(ints.mkString(","))//1,2,3,4
    //将数组中的每个元素打印
    for(elem <- ints){
      println(elem)
    }


    def printXXX(i:Int): Unit ={
      println(i)
    }
    //foreach方法会将数组中的每一个元素进行循环遍历,执行指定函数实现逻辑
    //ints.foreach(printXXX)
    ints.foreach((i:Int)=>{print(i+",")})//1,2,3,4,
    ints.foreach(print(_))
    ints.foreach(print)


    //增加元素
    ints.update(1,5)
    println(ints.mkString(","))


  }
}
//不可变数组
    //增加元素
    //产生了一个新的数组,不会对原有数组造成影响
    val ints1:Array[Int]= ints:+(5)
    println(ints1.mkString(","))
    //
    //修改数据
//    ints.update(1,5)
//    println(ints.mkString(","))
    //不可变数组
    //增加元素
    //产生了一个新的数组,不会对原有数组造成影响
    val ints1:Array[Int]= ints:+(5)
    println(ints1.mkString(","))
    //
    //修改数据
    ints.update(1,5)
    println(ints.mkString(","))


    //可变数组
    val arrayBuffer: ArrayBuffer[Int] = ArrayBuffer(5,6,7,8)
    // println(arrayBuffer(0))//5
     //修改值
    arrayBuffer(0)=9
    //将数组转化为字符串
    println(arrayBuffer.mkString(","))
     //循环遍历
     //arrayBuffer.foreach(println)
     //增加数据
     //val unit: Unit = arrayBuffer.insert(9)
     //返回是unit说明这是可变的
    val buffer:ArrayBuffer[Int]=arrayBuffer+=(9)
   println(arrayBuffer == buffer)//true
   arrayBuffer.foreach(println)
   val i:Int = arrayBuffer.remove(1)
   println("i = "+i )
   println(arrayBuffer.mkString(","))
     /*
     i = 6
     5,7,8
      */
     val unit: Unit = arrayBuffer.remove(1, 2)
    println(arrayBuffer.mkString(","))//5,8

    //可变数组和不可变数组的转换
    val buffer: mutable.Buffer[Int] = ints.toBuffer
    val array: Array[Int] = arrayBuffer.toArray

scala集合基本介绍

1.scala同时支持不可变集合和可变集合

//队列

import scala.collection.mutable

object Scala04_queue {
  def main(args: Array[String]): Unit = {
    val queue=  mutable.Queue(1,2,3,4)
    println("add before "+queue)
    //添加
    queue.enqueue(5)
    println("add after "+queue)
    //删除
    val i:Int = queue.dequeue()
    println("i="+i)
    println("delete after "+queue)

  }
}
set集合

object Scala05_set {
  def main(args: Array[String]): Unit = {
    var set=Set(1,2,3,4,5,6,7,8,8,9)
    println(set)//Set(5, 1, 6, 9, 2, 7, 3, 8, 4)  set为无序的,不可重复的
    //默认scala提供的set集合就是不可变的

    //增加数据
    println(set+11)//Set(5, 1, 6, 9, 2, 7, 3, 11, 8, 4)
    //删除数据
    println(set-11)//Set(5, 1, 6, 9, 2, 7, 3, 8, 4)
  }

}

元组

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JazBx3Cw-1618126542293)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409143308232.png)]

注意:从1开始

注意:遍历部分

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-miL0vdpd-1618126542293)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409143715471.png)]

object Scala07_tuble {
  def main(args: Array[String]): Unit = {
    val tuple1=(1,2,3,"gasdfsa","发斯蒂芬家")
    println(tuple1)//(1,2,3,gasdfsa,发斯蒂芬家)

    var tup1=2->"two"
    println(tup1)//(2,two)

    //元组的使用
    println(tuple1._1)//1
    println(tuple1.productElement(0))//1   访问元组的第一个元素,从0开始


    //遍历
    for (m<-tuple1.productIterator){
      println(m)
    }

  }
}

Map

HashMap

java中:

HashMap 是一个散列表(数组+链表),它存储的内容是键值对(key-value)映射,Java中的HashMap是无序的,key不能重复

Scala中的Map 和Java类似,也是一个散列表,它存储的内容也是键值对(key-value)映射,Scala中不可变的Map是有序的,可变的Map是无序的。

如果key存在,返回key对应的值。
如果key不存在,返回默认值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nWve4OMe-1618126542294)(C:\Users\86175\AppData\Roaming\Typora\typora-user-images\image-20210409145456245.png)]

val stringToInt: mutable.HashMap[String, Int] = mutable.HashMap(("A", 1), ("B", 2))

println(stringToInt("A"))//1

stringToInt += ("C"->3)

println(stringToInt)//Map(A -> 1, C -> 3, B -> 2)

stringToInt-=("C")
println(stringToInt)

set的其他方法

序号方法描述
1def +(elem: A): Set[A]为集合添加新元素,并创建一个新的集合,除非元素已存在
2def -(elem: A): Set[A]移除集合中的元素,并创建一个新的集合
3def contains(elem: A): Boolean如果元素在集合中存在,返回 true,否则返回 false。
4def &(that: Set[A]): Set[A]返回两个集合的交集
5def &~(that: Set[A]): Set[A]返回两个集合的差集
6def ++(elems: A): Set[A]合并两个集合
7def drop(n: Int): Set[A]]返回丢弃前n个元素新集合
8def dropRight(n: Int): Set[A]返回丢弃最后n个元素新集合
9def dropWhile(p: (A) => Boolean): Set[A]从左向右丢弃元素,直到条件p不成立
10def max: A //演示下查找最大元素
11def min: A //演示下查找最小元素
12def take(n: Int): Set[A]返回前 n 个元素
import scala.collection.immutable.HashMap
import scala.collection.mutable
import scala.collection.mutable.HashMap
object Scala08_HashMap {
  def main(args: Array[String]): Unit = {
    val map= mutable.Map(("A",1),("B",2),("C",3),("D",4))

//    println(map.mkString(","))//A -> 1,C -> 3,B -> 2
//
//    println(map.get("A"))//Some(1)
//    println(map.get("X"))//None
//
//    println(map.getOrElse("X","X"))

    map-=("B")
    println(map)//Map(D -> 4, A -> 1, C -> 3)
    

  }
}

容器进阶:

请将List(3,5,7) 中的所有元素都 * 2 ,将其结果放到一个新的集合中返回,即返回一个新的List(6,10,14), 请编写程序实现.

1import scala.collection.mutable.{HashMap, ListBuffer}
object Scala08_HashMap {
  def main(args: Array[String]): Unit = {
    val list = List(3,5,7)
    val buffer = ListBuffer[Int]()
    for(i <- list){
      buffer.append(i*2)
    }
    println(buffer.mkString(","))


  }
}


2val list=List(3,5,7)
    def f1(i:Int): Int ={
      2*i
    }
    val list2=list.map(f1)
    println(list2)

在Scala中可以通过map映射操作来解决:将集合中的每一个元素通过指定功能(函数)映射(转换)成新的结果集合这里其实就是所谓的将函数作为参数传递给另外一个函数,这是函数式编程的特点

//元组
    //Map(k -> v)
    //将无关的数据当成整体来使用
    //使用小括号将数据关联在一起,形成一个整体
    //元组中最多的元素数据个数是22
    val tuple:(String ,Int, String)=("张三",11111,"xxxxx")
    //访问元组中的数据,调用元组中的数据,调用相应的顺序编号
    println(tuple._1)
    println(tuple._2)


    //循环遍历
//    for (elem <- tuple.productIterator) {
//      println(elem)
//    }
    //如果元组中元素个数为2,那么称之为对偶,类似于Map中键值对
    val tuple1 = (1, "张三")


    val intToString: Map[Int, String] = Map((1, "bell"))
    intToString.foreach(tuple1=>{println(tuple1)})
  }
}

class User{
  var username:String=_
  var age:Int=_
}
集合方法

object Scala07_Method {
  def main(args: Array[String]): Unit = {
    val list: List[Int] = List(1, 2, 3, 4,3,3)
    //求和
    println("sum="+list.sum)
    //最大值
    println(list.max)
    //最小值
    println(list.min)
    //乘积
    println(list.product)
    //反转
    println(list.reverse)
    //
    //list.reduce()
    //TODO 分组(通过制定函数的返回值分组)
//    val intToInts: Map[Int, List[Int]] = list.groupBy(x => x)
//    intToInts.foreach(t=>{println(t._1+"="+t._2)})
    val strings: List[String] = List("11", "35", "14", "26")
//    val stringToStrings: Map[String, List[String]] = strings.groupBy(s => {
//      s.substring( 0, 1)
//    })
//
//    stringToStrings.foreach(t=>{println(t._1+"="+t._2)})

    //TODO 对偶数分组
    val intToInts: Map[Int, List[Int]] = list.groupBy(i => {
      i % 2
    })
    intToInts.foreach(t=>{println(t._1+"="+t._2)})
    //TODO 排序(按照指定规则排序)
//    val ints: List[Int] = list.sortBy(x => x)
//    println(ints.mkString(","))
//val strings1: List[String] = strings.sortBy(s => {
//  s.substring(1)
//})
//
//    println(strings1.mkString(","))

    //TODO sortWith(降序)
//    val ints: List[Int] = list.sortWith((x, y) => {
//      x > y
//    })
//    println(ints.mkString(","))
val strings1: List[String] = strings.sortWith((left, right) => (left.substring(1) > right.substring(1)))
    println(strings1.mkString(","))

    //TODO 迭代
    for (elem <- list.iterator) {
      println(elem)
    }

    //TODO map映射
    //x=>(x,x)
    val tuples: List[(Int, Int)] = list.map(x => (x, 1))
    val intToTuples: Map[Int, List[(Int, Int)]] = tuples.groupBy(t => t._1)
    val intToInt: Map[Int, Int] = intToTuples.map(t => (t._1, t._2.size))
    println(intToInt.mkString(","))

    //println(intToTuples)

    //println(tuples.mkString(","))

  }
}



//TODO  对集合的数据进行筛选,true保留,false过滤
    val ints1: List[Int] = ints.filter(x =>{x%2==1})
    println(ints1.mkString(","))

    //TODO  拉链 zip

    val ints2: List[Int] = List(1, 2, 3)
    val ints3: List[Int] = List(3,4, 5, 6,7)
    //形成了元组
    val tuples: List[(Int, Int)] = ints2.zip(ints3)
    println(tuples.mkString(","))//(1,4),(2,5),(3,6)

    //TODO  合并

    val ints4: List[Int] = ints2.union(ints3)
    println(ints4.mkString(","))//1,2,3,3,4,5,6,7
    //TODO 交集
    val ints5: List[Int] = ints2.intersect(ints3)
    println(ints5.mkString(","))

    //TODO 差集(注意要保留哪些集合中的元素)
    val ints6: List[Int] = ints2.diff(ints3)
    println(ints6.mkString(","))//1,2


val ints: List[Int] = List(1, 2, 3, 4)
    //折叠 fold 减少数据
    /*
    fold方法可以传递2个部分的参数,第一个部分表示集合之外的数据
    第二部分的参数表示数据进行的逻辑处理
     */
    val i: Int = ints.fold(100)(_ - _)
    println(i)//90
    val i1: Int = ints.foldRight(10)(_ - _)
    println(i1)//8   (1-(2-(3-(4-10))))
  }


//TODO  将2个Map进行合并,相同key做累加,不同的key直接增加
    val stringToInt: mutable.Map[String, Int] = mutable.Map("a" -> 1, "b" -> 2, "c" -> 3)
    val stringToInt1: mutable.Map[String, Int] = mutable.Map("a" -> 3, "c" -> 2, "d" -> 1)

    val stringToInt2: mutable.Map[String, Int] = stringToInt.foldLeft(stringToInt1)((map, t) => {
      //map集合设置的方式,map(key)=value
      map(t._1) = map.getOrElse(t._1, 0) + t._2
      map
    })
    println(stringToInt2.mkString(","))

//必会

//TODO WordCount
//对集合中的字符串统计出现的次数,并且按照出现次数降序排列,取前3
val strings2: List[String] = List("Hello", "Scala", "Python", "World", "Scala", "Kafla", "Dir")


//将相同的单词放置在一起(分组)
//   (Hello,List("Hello","Hello"))
val tupleToStrings: Map[(String, String), List[String]] = strings2.groupBy(x => (x, x))
//将数据结构进行转换
val tupleToInt: Map[(String, String), Int] = tupleToStrings.map(t => {
  (t._1, t._2.size)
})
//将数据进行排序
val tuples: List[((String, String), Int)] = tupleToInt.toList.sortWith((left, right) => {
  left._2 > right._2
})
//取排序完成后的前3条数据
val tuples1: List[((String, String), Int)] = tuples.take(3)



scala中的模式匹配

细节和注意事项:

1)如果所有case都不匹配,那么执行case _ 分支,类似于Java中default语句

2)如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError

3)每个case中,不用break语句,自动中断case

4)可以在match中使用其它类型,而不仅仅是字符,可以是表达式
=> 类似于 java swtich 的 :

5)=> 后面的代码块到下一个case, 是作为一个整体执行,可以使用{} 括起来,也可以不括。

object Scala_switch_1 {
  def main(args: Array[String]): Unit = {
    val oper='#'
    val n1=20
    val n2=10
    var res = 0
    oper match{
      case '+' => res=n1+n2
      case '-' => res=n1-n2
      case '*' => res=n1*n2
      case '/'=>res=n1/n2
      case _ => println("oper error")
    }
    println("res="+res)

  }
}
for (ch <- "+-3!") {
  var sign = 0
  var digit = 0
  ch match {
    case '+' => sign = 1
    case '-' => sign = -1
    case _ if ch.toString.equals("3") => digit = 3
    case _ => sign = 2
  }
  println(ch + " " + sign + " " + digit)
}
结果:
+ 1 0
- -1 0
3 0 3
! 2 0
val ch = 'V'
ch match {
  case '+' => println("ok~")
  case mychar => println("ok~" + mychar)
  case _ => println ("ok~~")
}

结果:
ok~V

可以匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf方法

1)Map[String, Int] 和Map[Int, String]是两种不同的类型,其它类推。
2)在进行类型匹配时,编译器会预先检测是否有可能的匹配,如果没有则报错.

匹配数组:

  1. Array(0) 匹配只有一个元素且为0的数组。
  2. Array(x,y) 匹配数组有两个元素,并将两个元素赋值为x和y。当然可以依次类推Array(x,y,z) 匹配数组有3个元素的等等…
  3. Array(0,_*) 匹配数组以0开始
for(arr <- Array(Array(0),Array(1,0),Array(0,1,0),Array(1,1,0),Array(1,1,0,1))){
  val result = arr match {
    case Array(0) => 0
    case Array(x,y) => x+"="+y
    case Array(0,_*) => "以0开头的数组"
    case _ => "什么集合都不是"
  }
  println(arr+"是"+result)
}
case x :: Nil => {
  println("匹配到" + (x::Nil))
  x :: Nil //直接返回
}



  for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0))) {
    val result = list match {
      case 0 :: Nil => "0" 
      case x :: y :: Nil => x + " " + y
      case 0 :: tail => "0 ..."
      case _ => "something else"
    }
    println(result)
  }
for (pair <- Array((0, 1), (1, 0), (2, 1),(1,0,2))) {
  val result = pair match {
    case (0, _) => "0 ..."
    case (y, 0) => y
    case (a,b) => (b,a)
    case _ => "other"
  }
  println(result)
}
结果
0 ...
1
(1,2)
other
object Square {
  def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
  def apply(z: Double): Double = z * z
}

// 模式匹配使用:
val number:Double = 9
number match {
  case Square(n) => println(n)
  case _ => println("nothing matched")
}

对象匹配:

  1. 构建对象时apply会被调用 ,比如 val n1 = Square(5)

  2. 当将 Square(n) 写在 case 后时[case Square(n) => xxx],会默认调用unapply 方法(对象提取器)

  3. number 会被 传递给def unapply(z: Double) 的 z 形参

  4. 如果返回的是Some集合,则unapply提取器返回的结果会返回给n这个形参

  5. case中对象的unapply方法(提取器)返回some集合则为匹配成功

  6. 返回none集合则为匹配失败

object Names {

  // unapplySeq
  def unapplySeq(str: String): Option[Seq[String]] = {
    if (str.contains(","))
      Some(str.split(","))
    else
      None
  }
}


val namesString = "Alice,Bob"
namesString match {
  case Names(first, second) => {
    println("three people's names")
    // 打印字符串
    println(s"$first $second ")
  }
  case _ => println("nothing matched")
}
  1. 当case 后面的对象提取器方法的参数为多个,则会默认调用def unapplySeq() 方法

  2. 如果unapplySeq返回是Some,获取其中的值,判断得到的sequence中的元素的个数是否是三个,如果是三个,则把三个元素分别取出,赋值给first,second和third

  3. 其它的规则不变.

样例类:

  • 样例类仍然是类
  • 样例类用case关键字进行声明
  • 样例类是为模式匹配(对象)而优化的类
  • 构造器中的每一个参数都成为val——除非它被显式地声明为var
  • 在样例类对应的伴生对象中提供apply方法让你不用new关键字就能构造出相应的对象
  • 提供unapply方法让模式匹配可以工作
  • 自动生成toString、equals、hashCode和copy方法(有点类似模板类,直接给生成,供程序员使用)
  • 除上述外,样例类和其他类完全一样。你可以添加方法和字段,扩展它们
abstract class Amount
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
case object NoAmount extends Amount

for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) {
  val result = amt match {
    case Dollar(v) => "$" + v
    case Currency(v, u) => v + " " + u
    case NoAmount => ""
  }
  println(amt + ": " + result)
}


输出结果:
Dollar(1000.0): $1000.0
Currency(1000.0,RMB): 1000.0 RMB
NoAmount:
val amt = Currency(29.95, "RMB")

val amt1 = amt.copy()
val amt2 = amt.copy(value = 19.95)
val amt3 = amt.copy(unit = "英镑")

println(amt)
println(amt1)
println(amt2)
println(amt3)

输出结果:
Currency(29.95,RMB)
Currency(29.95,RMB)
Currency(19.95,RMB)
Currency(29.95,英镑)


什么是中置表达式?1 + 2,这就是一个中置表达式。如果unapply方法产出一个元组,你可以在case语句中使用中置表示法。比如可以匹配一个List序列

var list = List(1, 3, 5, 9)
list match {
  case first :: second :: rest => println(first + "**" + second + "**" + rest)
  case _ => println("匹配不到...")
}

输出结果:
1**3**List(5, 9)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RE:0-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值