小工具知识网

当前位置: 首页 > 行业知识 > 大数据开发语言Scala(一)——scala入门

行业知识

大数据开发语言Scala(一)——scala入门

2026-11-02 00:22:14 来源:互联网转载

���了,基础配置不想写了,直接抄了→Scala的环境搭建

这里需要注意的是,创建新项目时,不要用默认的Class类,用Object,原因看→scala中的object为什么可以直接运行

一、Scala简介

1.1 图解Scala和Java的关系

1.2 关键字说明

package: 包,等同于java中的package

object:关键字,声明一个单例对象(伴生对象)

main方法:从外部可以直接调用执行的方法

def 方法名称 ( 参数名称 : 参数类型 ) : 返回值类型 = { 方法体 }

Scala 完全面向对象,故scala去掉了Java中非面向对象的元素,如static关键字,void类型

1) static

scala无static关键字,由object实现类似静态方法的功能(类名.方法名)

class关键字和Java中的class关键字作用相同,用来定义一个类

2) void

对于无返回值的函数,scala定义其返回值类型为Unit类型

1.3 代码案例

package com.scala.chapter1object Hello {  def main(args: Array[String]): Unit = {    println("hello scala")    System.out.println("hello scala")  }}

1.4 Scala语言特点

Scala是一门以Java虚拟机 (JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言(静态语言需要提前编译的如: Java、C、C++等,动态语言如:JS)。

1)Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。 (多范式,就是多种编程方法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法。)

2)Scala源代码 (.scala) 会被编译成Java字节码 (.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝对接。

3)Scala单作为一门语言来看,非常的简洁高效

4)Scala在设计时,马丁·奥德斯基是参考了Java的设计思想,可以说Scala是源于Java,同时马丁·奥德斯基也加入了自己的思想,将函数式编程语言的特点融合到JAVA中,因此,对于学习过Java的同学,只要在学习Scala的过程中,搞清楚Scala和Java相同点和不同点,就可以快速的掌握Scala这门语言。

二、变量和数据类型

Any: 所有类型的超类(顶级类型)

AnyVal: 值类型的超类

AnyRef: 引用类型的超类,对应java.lang.Object

Unit: 无值,类似java中的void

Nothing: 所有类型的子类

Null: 表示null或空引用

2.1 注释

Scala注释使用和Java完全一样。

注释是一个程序员必须要具有的良好编程习惯。将自己的思想通过注释先整理出来,再用代码去体现。

1)基本语法

(1)单行注释://(2)多行注释:/* */(3)文档注释:/**            *            */

2)案例实操

object Test1 {def main(args: Array[String]): Unit = {//单行注释println("单行")//多行/*println("多行")*///文档注释/**   * println("文档注释")   */}}

3) 代码规范

(1)使用一次tab操作,实现缩进,默认整体向右边移动,用shift+tab整体向左移

(2)或者使用ctrl + alt + L来进行格式化

(3)运算符两边习惯性各加一个空格。比如:2 + 4 * 5

(4)一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅

2.2 变量和常量(重点)

常量:在程序执行的过程中,其值不会被改变的变量

1)基本语法

​ var 变量名 [: 变量类型] = 初始值 var i:Int = 10

​ val 常量名 [: 常量类型] = 初始值 val j:Int = 20

​ 注意:能用常量的地方不用变量

2)案例实操

(1)声明变量时,类型可以省略,编译器自动推导,即类型推导

(2)类型确定后,就不能修改,说明Scala是强数据类型语言。

(3)变量声明时,必须要有初始值

(4)在声明/定义一个变量时,可以使用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可改。

object TestValueTransfer {def main(args: Array[String]): Unit = {var n = 1 + 2.2222println(n) //Doublevar n2: Double = 2.2222//    var n3: Int = n2 //报错var n4 : Byte = 44//    var c1 : Char = n4 //报错var n5 : Int = n4var n6 : Byte = 66var c2 : Char = 22//    var n : Short = n6 + c2  //报错,结果是Int类型//    var n7 : Short = 10 + 20  //报错,byte,short,char他们三者可以计算,在计算时首先转换为int类型。}}

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

object TestVar {def main(args: Array[String]): Unit = {var age = 22age = 29//    age = "hh"  //报错var n1 = 1 //可变n1 = 2val n2 = 2 //不可变//n2 = 3//p1 是var修饰的,p1的属性可以变,p1本身也可以变var p1 = new Person()p1.name = "varp1"p1 = nullval p2 = new Person()p2.name = "valp2"//    p2 = null //报错}class Person {var name: String = "who"}}

2.3 标识符的命名规范

Scala对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可以起名字的地方都叫标识符。

1)命名规则

Scala中的标识符声明,基本和Java是一致的,但是细节上会有所变化,有以下三种规则:

(1)以字母或者下划线开头,后接字母、数字、下划线

(2)以操作符开头,且只包含操作符(+ - * / # !等)

(3)用反引号....包括的任意字符串,即使是Scala关键字(39个)也可以

• package, import, class, object, trait, extends, with, type, for• private, protected, abstract, sealed, final, implicit, lazy, override• try, catch, finally, throw• if, else, match, case, do, while, for, return, yield• def, val, var• this, super• new• true, false, null

2)案例实操

需求:判断hello、Hello12、1hello、h-b、x h、h_4、ab、Int、、+-/#!、+-/#!1、if、if,这些名字是否合法。

object TestName {  def main(args: Array[String]): Unit = {    //1.以字母或者下划线开头,后接字母、数字、下划线    var hello: String = ""    var hello2: String = " "    //    var 1 hello:String = ""  数字不能开头    //    var h - b: String = ""  不能用-    //    var x h: String = ""  不能用空格    var h_4: String = ""    val _ab: String = ""    var Int: String = "" //ok 因为在Scala中Int是预定义的字符,不是关键字,但不推荐    var _: String = "" // ok 单独一个下划线不可以作为标识符,因为_被认为是一个方法    //2.以操作符开头,且只包含操作符(+ - * / # ! 等)    var +*-/#! : String = ""    //    var +*-/#!1 : String = "" 以操作符开头必须都是操作符    //3.用反引号`...`包括的任意字符串,即使是Scala关键字(39)个也可以    //    var if:String = ""  不用用关键字    var `if`: String = ""  }}

2.4 字符串输出

1)基本语法

(1)字符串,通过+号连接

(2)printf用法:字符串,通过%传值。

(3)字符串模板(插值字符串):通过$获取变量值

2)案例实操

object TestCharType {def main(args: Array[String]): Unit = {var name: String = "zhangsan"var age: Int = 22//1.字符串 通过 + 号连接println(name + " " + age)//2.printf 用法字符串,通过%传值printf("name=%s age=%d\n", name, age)//3.字符串,通过$引用//多行字符串,在Scala中,利用三个双引号包围多行字符串就可以实现。//输入的内容,带有空格、\t之类,导致每一行的开始位置不能整洁对齐。//应用scala的stripMargin方法,在scala中stripMargin默认是“|”作为连接符,//在多行换行的行头前面加一个“|”符号即可。val s ="""  | select  | name  |,  |age  |from user  |where name = "zhangsan"""".stripMarginprintln(s)//如果需要对变量进行运算,那么可以加${}val s1 =s"""   | select   | name   |,   |age   |from user   |where name="$name" and age=${age + 2}""".stripMarginval s2 = s"name=$name"println(s2)}}

2.5 键盘输入

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

1)基本语法

StdIn.readLine()、StdIn.readShort()、StdIn.readDouble()

2)案例实操

需求:可以从控制台接收用户信息,【姓名,年龄,薪水】。

import scala.io.StdInobject TestInput {def main(args: Array[String]): Unit = {//    输入姓名println("input name:")var name = StdIn.readLine()//    输入年龄println("input age:")var age = StdIn.readShort()//    输入薪水println("input sal:")var sal = StdIn.readDouble()//    打印println("name=" + name)println("age=" + age)println("sal=" + sal)}}

从文件中读取数据:

import scala.io.Source;Source.fromFile("C:\Users\90513\Desktop\datas.csv").foreach(print)

2.6 数据类型(重点)

  • Java 数据类型

    Java基本数据类型:char、byte、short、int、long、float、double、boolean

    Java引用类型:(对象类型)

    由于Java有基本类型,而且基本类型不是真正意义的对象,即使后面产生了基本类型的包装类,但是仍然存在基本数据类型,所以Java语言并不是真正意义上的面向对象

    Java基本类型的包装类:Character、Byte、Short、Integer、Long、Float、Double、Boolean

    注意:Java中基本类型和引用类型没有共同的祖先。

    • Scala 数据类型

      2.7 整数类型(Byte、Short、Int、Long)

      Scala的整数类型就是用于存放整数值的,比如12,30,3456等等。

      1)整型分类

      数据类型

      描述

      Byte [1]

      8位有符号补码整数。数值区间为 -128 到 127

      Short [2]

      16位有符号补码整数。数值区间为 -32768 到 32767

      Int [4]

      32位有符号补码整数。数值区间为 -2147483648 到 2147483647

      Long [8]

      64位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 = 2的(64-1)次方-1

      2)案例实操

      (1)Scala各整数类型有固定的表示范围和字段长度,不受具体操作的影响,以保证Scala程序的可移植性。

      (2)Scala的整型,默认为Int型,声明Long型,须后加‘l’或‘L’

      object TestDataType {def main(args: Array[String]): Unit = {// 正确var n1: Byte = 127var n2: Byte = -128// 错误//    var n3:Byte = 128//    var n4:Byte = -129// Scala的整型,默认为Int型,声明Long型,然后加”i“ 或者 ”L“var n5 = 10println(n5)var n6 = 98989898989898989Lprintln(n6)var n7 = 2.43434309898fvar n8 = 2.4343662343223println(n7)println(n8)var God = new God()God = null//var n1 : Int = null //错误//println("n1:" + n1)}class God {}}

      (3)Scala程序中变量常声明为Int型,除非不足以表示大数,才使用Long

      2.8 浮点类型(Float、Double)

      Scala的浮点类型可以表示一个小数,比如123.4f,7.8,0.12等等。

      1)浮点型分类

      数据类型

      描述

      Float [4]

      32 位, IEEE 754标准的单精度浮点数

      Double [8]

      64 位 IEEE 754标准的双精度浮点数

      2)案例实操

      Scala的浮点型常量默认为Double型,声明Float型常量,须后加‘f’或‘F’。

      object TestDataType {def main(args: Array[String]): Unit = {// 正确var n1: Byte = 127var n2: Byte = -128// 错误//    var n3:Byte = 128//    var n4:Byte = -129// Scala的整型,默认为Int型,声明Long型,然后加”i“ 或者 ”L“var n5 = 10println(n5)var n6 = 98989898989898989Lprintln(n6)var n7 = 2.43434309898fvar n8 = 2.4343662343223println(n7)println(n8)var God = new God()God = null//var n1 : Int = null //错误//println("n1:" + n1)}class God {}}

      2.9 字符类型(Char)

      1)基本说明

      字符类型可以表示单个字符,字符类型是Char。

      2)案例实操

      (1)字符常量是用单引号 ’ ’ 括起来的单个字符。

      (2)\t :一个制表位,实现对齐的功能

      (3)\n :换行符

      (4)\\ :表示\

      (5)" :表示"

      package com.atguigu.chapter1object TestCharType2 {def main(args: Array[String]): Unit = {var c1: Char = 'a'println("c1=" + c1)//注意:这里涉及自动类型提升,其实编译器可以自定判断是否超出范围//不过idea提示报错var c2: Char = 'a' + 1println(c2)//    \t :一个制表位,实现对齐的功能println("姓名\t年龄")//   \n :换行符println("西门庆\n潘金莲")//(4)\ :表示\println("c:\天黑了\饿狼来了")//(5)\" :表示"println("你过来:\"看我一拳打***你\"")}}

      2.10 布尔类型:Boolean

      1)基本说明

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

      (2)boolean类型占1个字节。

      2)案例实操

      object TestBooleanType {def main(args: Array[String]): Unit = {var isResult : Boolean = falsevar isResult2 : Boolean = true}}

      2.11 Unit类型、Null类型和Nothing类型(重点)

      1)基本说明

      数据类型

      描述

      Unit

      表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。

      Null

      null , Null 类型只有一个实例值null

      Nothing

      Nothing类型在Scala的类层级最低端;它是任何其他类型的子类型。 当一个函数,我们确定没有正常的返回值(如抛出异常),可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性)

      在Java中有时候有返回值,如int,但有些情况下会抛出异常。为了兼容多种可能性,就可以使用nothing类型。

      2)案例实操

      (1)Unit类型用来标识过程,也就是没有明确返回值的函数。

      由此可见,Unit类似于Java里的void。Unit只有一个实例——( ),这个实例也没有实质意义

      def m1():Unit={    println("m1被执行")}val a:Unit=m1()println("a="+a)// 输出:a=()

      (2)Null类只有一个实例对象,Null类似于Java中的null引用。Null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)

      object TestDataType {def main(args: Array[String]): Unit = {// 正确var n1: Byte = 127var n2: Byte = -128// 错误//    var n3:Byte = 128//    var n4:Byte = -129// Scala的整型,默认为Int型,声明Long型,然后加”i“ 或者 ”L“var n5 = 10println(n5)var n6 = 98989898989898989Lprintln(n6)var n7 = 2.43434309898fvar n8 = 2.4343662343223println(n7)println(n8)// null可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)var God = new God()God = null//    var n1: Int = null //错误//    println("n1:" + n1)}class God {}}

      (3)Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容。

      object TestSpecialType {def test(): Nothing = {throw new Exception}test()}}

      2.12 类型转换

      2.12.1 数值类型自动转换

      当Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:

      1)基本说明

      (1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。

      (2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。

      (3)(byte,short)和char之间不会相互自动转换。

      (4)byte,short,char他们三者可以计算,在计算时首先转换为int类型。

      2)案例实操

      object TestValueTransfer {def main(args: Array[String]): Unit = {//(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数值类型,然后再进行计算。var n = 1 + 2.2222println(n) //Double//(2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。var n2: Double = 2.2222//    var n3: Int = n2 //报错//(3)(byte,short)和char之间不会相互自动转换。var n4: Byte = 44//    var c1 : Char = n4 //报错var n5: Int = n4//(4)byte,short,char他们三者可以计算,在计算时首先转换为int类型。var n6: Byte = 66var c2: Char = 22//    var n : Short = n6 + c2  //报错,结果是Int类型//    var n7 : Short = 10 + 20  //报错,byte,short,char他们三者可以计算,在计算时首先转换为int类型。}}

      注意:Scala还提供了非常强大的隐式转换机制(隐式函数,隐式类等),我们放在高级部分专门用一个章节来讲解。

      2.12.2 强制类型转换

      1)基本说明

      自动类型转换的逆过程,将精度大的数值类型转换为精度小的数值类型。使用时要加上强制转函数,但可能造成精度降低或溢出,格外要注意。

      2)案例实操

      (1)将数据由高精度转换为低精度,就需要使用到强制转换

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

      object TestForceTransfer {def main(args: Array[String]): Unit = {//(1)将数据由高精度转换为低精度,就需要使用到强制转换var n1: Int = 2.5.toInt // 这个存在精度损失//(2)强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级var r1: Int = 10 * 3.5.toInt + 6 * 1.5.toInt // 10 *3 + 6*1 = 36var r2: Int = (10 * 3.5 + 6 * 1.5).toInt // 44.0.toInt = 44println("r1=" + r1 + " r2=" + r2)}}

      2.12.3 数值类型和String类型间转换

      1)基本说明

      在程序开发中,我们经常需要将基本数值类型转成String类型。或者将String类型转成基本数值类型。

      2)案例实操

      (1)基本类型转String类型(语法:将基本类型的值+“” 即可)

      (2)String类型转基本数值类型(语法:s1.toInt、s1.toFloat、s1.toDouble、s1.toByte、s1.toLong、s1.toShort)

      object TestStringTransfer {def main(args: Array[String]): Unit = {//(1)基本类型转String类型(语法:将基本类型的值+"" 即可)var str1: String = true + "你kin"println(str1)var str2: String = 4.444 + "拜拜"println(str2)var str3: String = 4444 + ""println(str3)//(2)String类型转基本数值类型(语法:调用相关API)var s1: String = "11"var n1: Byte = s1.toBytevar n2: Short = s1.toShortvar n3: Int = s1.toIntvar n4: Long = s1.toLongprintln(s1)println(n1)println(n2)println(n3)println(n4)}}

      (3)注意事项

      在将String类型转成基本数值类型时,要确保String类型能够转成有效的数据,比如我们可以把"123",转成一个整数,但是不能把"hello"转成一个整数。

      var n5:Int = “12.6”.toInt会出现NumberFormatException异常。

      2.13 字符串String

      Scala中本身没有String数据类型,字符串本质上是Java String。和Java String 一样,String是一个不可变对象,该对象不可修改。

      三、运算符

      Scala运算符的使用和Java运算符的使用基本相同,只有个别细节上不同。

      3.1 算术运算符

      1)基本语法

      运算符

      运算

      范例

      结果

      +

      正号

      +3

      3

      -

      负号

      b=4; -b

      -4

      +

      加

      5+5

      10

      -

      减

      6-4

      2

      *

      乘

      3*4

      12

      /

      除

      5/5

      1

      %

      取模(取余)

      7%5

      2

      +

      字符串相加

      “He”+”llo”

      “Hello”

      (1)对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。

      (2)对一个数取模a%b,和Java的取模规则一样。

      2)案例实操

      object TestArithmetic {def main(args: Array[String]): Unit = {//    1)对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整数部分而舍弃小数部分。var r1: Int = 10 / 3println(r1) //3var r2: Double = 10 / 3println(r2) //3.0var r3: Double = 10.0 / 3println(r3) //3.3333333333333335println(r3.formatted("%.2f")) //3.33  含义:保留小数点2位,使用四舍五入//(2)对一个数取模a%b,和Java的取模规则一样。var r4 = 10 % 3println(r4) //1}}

      3.2 关系运算符(比较运算符)

      1)基本语法

      运算符

      运算

      范例

      结果

      ==

      相等于

      4==3

      false

      !=

      不等于

      4!=3

      true

      3

      true

      =3

      true

      2)案例实操

      (1)需求1:

      object TestRelation {def main(args: Array[String]): Unit = {// 测试:>、>=、= b) // trueprintln(a 

      &=

      按位与后赋值

      C &= 2 等于 C = C & 2

      ^=

      按位异或后赋值

      C ^= 2 等于 C = C ^ 2

      |=

      按位或后赋值

      C |= 2 等于 C = C | 2

      注意:Scala中没有++、–操作符,可以通过+=、-=来实现同样的效果;

      2)案例实操

      object TestAssignment {def main(args: Array[String]): Unit = {var r1 = 11//  没有++r1 += 1 //12println(r1)// 没有--r1 -= 2 //10println(r1)}}

      3.5 位运算符

      1)基本语法

      下表中变量 a 为 60,b 为 13。

      运算符

      描述

      实例

      &

      按位与运算符

      (a & b) 输出结果 12 ,二进制解释: 0000 1100

      |

      按位或运算符

      (a | b) 输出结果 61 ,二进制解释: 0011 1101

      ^

      按位异或运算符

      (a ^ b) 输出结果 49 ,二进制解释: 0011 0001

      ~

      按位取反运算符

      (~a ) 输出结果 -61 ,二进制解释: 1100 0011, 在一个有符号二进制数的补码形式。

      > 2 输出结果 15 ,二进制解释: 0000 1111

      >>>

      无符号右移

      a >>>2 输出结果 15, 二进制解释: 0000 1111

      2)案例实操

      object TestPositon {def main(args: Array[String]): Unit = {//  测试:1000 10000var n1: Int = 8n1 = n1 = 18 && age   

      (2)需求2:Scala中if else表达式其实是有返回值的,具体返回值取决于满足条件的代码体的最后一行内容。

      val res :String = if (age = 18 && age   

      (3)需求3:Scala中返回值类型不一致,取它们共同的祖先类型。

      val res :Any = if (age = 18 && age   

      (4)需求4:Java中的三元运算符可以用if else实现

      如果大括号{}内的逻辑代码只有一行,大括号可以省略。如果省略大括号,if只对最近的一行逻辑代码起作用。

      // Java中三元运算符:a?b:c// 如:int result = flag ? 1 : 0// Scalaval res:String = if(age>=18) "成年" else "未成年"println(res)

      4.2 嵌套分支

      在一个分支结构中又完整的嵌套了另一个完整的分支结构,里面的分支的结构称为内层。分支外面的分支结构称为外层分支。嵌套分支不要超过3层。

      1)基本语法

      if(){
      if(){
      }else{
      }
      }

      2)案例实操

      需求:如果输入的年龄小于18,返回“童年”。如果输入的年龄大于等于18,需要再判断:如果年龄大于等于18且小于30,返回“中年”;如果其他,返回“老年”。

      import scala.io.StdInobject TestIfElse {def main(args: Array[String]): Unit = {// Scalaprintln("input age:")var age = StdIn.readShort()val res: Any = if (age = 18 && age     

      4.3 Switch分支结构

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

      模式匹配涉及到的知识点较为综合,因此我们放在后面讲解。

      4.4 For循环控制

      Scala也为for循环这一常见的控制结构提供了非常多的特性,这些for循环的特性被称为for推导式或for表达式。

      4.4.1 范围数据循环(To)

      1)基本语法

      // java for循环语法for(int i = 0; i  Int => Int = fun4 _

      5.4 偏函数

      所谓偏函数,就是以原函数为基础,将某个位置上的参数固定住(默认是从第一个参数固定),后续参数重新扩展传递给原函数,对外则是生成一个新函数。

      使用collect方法并行计算

      // 普通方法定义一个函数def funPartition:(Int, Int)=> Int= { }def funPartition:PartialFunction[String,Int] = {    case "hello" => 1    case "world" => 2    case _       => 3}println(funPartition("scala"))        // 输出3// 输入一个数组,并进行计算val strings = Array("hello","java","scala","world")val ints: Array[Int] = strings.collect(funPartition)println(ints.mkString(","))        // 1,3,3,2

      六、面向对象

      Scala的面向对象思想和Java的面向对象思想和概念是一致的。

      Scala中语法和Java不同,补充了更多的功能。

      6.1 Scala包

      1)基本语法

      package 包名

      2)Scala包的三大作用(和Java一样)

      (1)区分相同名字的类

      (2)当类很多时,可以很好的管理类

      (3)控制访问范围

      6.1.1 包的命名

      1)命名规则

      只能包含数字、字母、下划线、小圆点.,但不能用数字开头,也不要使用关键字。

      2)案例实操

      demo.class.exec1 //错误,因为 class 关键字
      demo.12a //错误,数字开头

      3)命名规范

      一般是小写字母+小圆点

      com.公司名.项目名.业务模块名

      6.1.2 包说明(包语句)

      1)说明

      Scala有两种包的管理风格,一种方式和Java的包管理风格相同,每个源文件一个包(包名和源文件所在路径不要求必须一致),包名用“.”进行分隔以表示包的层级关系,如com.atguigu.scala。另一种风格,通过嵌套的风格表示层级关系,如下:

      package com{    package baidu{        package scala{        }    }}

      第二种风格有以下特点:

      (1)一个源文件中可以声明多个package

      (2)子包中的类可以直接访问父包中的内容,而无需导包

      6.1.3 包对象

      在Scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问。

      1)定义

      package object com{    val shareValue="share"    def shareMethod()={}}

      2) 说明

      若使用Java的包管理风格,则包对象一般定义在其对应包下的package.scala文件中,包对象名与包名保持一致。

      6.1.4 导包说明

      1)和Java一样,可以在顶部使用import导入,在这个文件中的所有类都可以使用。

      2)局部导入:什么时候使用,什么时候导入。在其作用范围内都可以使用

      3)通配符导入:import java.util._

      4)给类起名:import java.util.{ArrayList=>JL}

      5)屏蔽类:import java.util.{ArrayList =>,}

      6)导入相同包的多个类:import java.util.{HashSet, ArrayList}

      7)导入包的绝对路径:new root.java.util.HashMap

      6.2 类和对象

      类:可以看成一个模板

      对象:表示具体的事物

      6.2.1 定义类

      0)回顾:Java中的类

      如果类是public的,则必须和文件名一致。

      一般,一个.java有一个public类

      注意:Scala中没有public,一个.scala中可以写多个类。

      1)基本语法

      [修饰符] class类名 {    类体}

      说明

      (1)Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)

      (2)一个Scala源文件可以包含多个类

      2)案例实操

      //    (1)Scala语法中,类并不声明public,所有这些类都具有共有可见性(即默认就是public)class Person {    // 定义属性    private var name: String = "alice"    var age: Int = _    var sex: String = _}//    (2) 一个Scala源文件可以包含多个类class Teacher {}def main(args: Array[String]): Unit = {    // 创建一个对象    val stu = new Student;    stu.name        // error,不能访问    stu.age    stu.sex}

      6.3 封装

      封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。Java封装操作如下,

      (1)将属性进行私有化

      (2)提供一个公共的set方法,用于对属性赋值

      (3)提供一个公共的get方法,用于获取属性的值

      Scala中的public属性,底层实际为private,并通过get方法(obj.field())和set方法(obj.field_=(value))对其进行操作。所以Scala并不推荐将属性设为private,再为其设置public的get和set方法的做法。但由于很多Java框架都利用反射调用getXXX和setXXX方法,有时候为了和这些框架兼容,也会为Scala的属性设置getXXX和setXXX方法(通过@BeanProperty注解实现)。

      6.3.1 访问权限

      1)说明

      在Java中,访问权限分为:public,private,protected和默认。在Scala中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。

      (1)Scala 中属性和方法的默认访问权限为public,但Scala中无public关键字。

      (2)private为私有权限,只在类的内部和伴生对象中可用。

      (3)protected为受保护权限,Scala中受保护权限比Java中更严格,同类、子类可以访问,同包无法访问。

      (4)private[包名]增加包访问权限,包名下的其他类也可以使用

      6.3.3 创建对象

      1)基本语法

      val | var 对象名 [:类型] = new类型()

      2)案例实操

      (1)val修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。

      (2)var修饰对象,可以修改对象的引用和修改对象的属性值

      (3)自动推导变量类型不能多态,所以多态需要显示声明

      class Person05 {    var name: String = "taotao"}object Person05 {    def main(args: Array[String]): Unit = {//    val 修饰对象,不能改变对象的引用(即内存地址),可以改变对象属性的值。        val person = new Person05()        person.name = "bingbing"    }}

      6.3.4 构造器

      和Java一样,Scala构造对象也需要调用构造方法,并且可以有任意多个构造方法。

      Scala类的构造器包括:主构造器和辅助构造器

      1)基本语法

      class 类名 (形参列表){ / /主构造器

      // 类体

      def this(形参列表){ // 辅助构造器

      }

      def this(形参列表){ // 辅助构造器可以有多个。。。

      }
      }

      说明:

      (1)辅助构造器,函数的名称this,可以有多个,编译器通过参数的个数及类型来区分。

      (2)辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

      (3)构造器调用其他另外的构造器,要求被调用构造器必须提前声明

      2)案例实操

      // 定义一个类class Student{    // 定义属性    var name: String = _    var age: Int = _    println("1. 主构造方法被调用")        // 声明辅助构造方法    def this(name: String){        this()    // 直接调用主构造器        println("2. 辅助构造方法一被调用")        this.name = name    }    def this(name: String, age:Int){        this(name)        println("3. 辅助构造方法二被调用")        this.age = age    }}

      6.3.5 构造器参数

      1)说明

      Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰

      (1)未用任何修饰符修饰,这个参数就是一个局部变量

      (2)var修饰参数,作为类的成员属性使用,可以修改

      (3)val修饰参数,作为类只读属性使用,不能修改

      2)案例实操

      // 定义类// 无参构造器class Student{    // 单独定义属性    var name : String = _    var age : Int = _}// 上面等价于:class Student(var name: String, var age: Int)val stu = new Student("bob",20)

      6.4 继承

      1)基本语法

      class 子类名 extends 父类名 { 类体 }

      (1)子类继承父类的属性和方法

      (2)scala是单继承

      2)案例实操

      (1)子类继承父类的属性和方法

      (2)继承的调用顺序:父类构造器->子类构造器

      6.5 抽象属性和抽象方法abstract

      6.5.1 抽象属性和抽象方法

      1)基本语法

      ​ (1)定义抽象类:abstract class Person{} //通过abstract关键字标记抽象类

      ​ (2)定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性

      ​ (3)定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法

      abstract class Person09 {    val name: String  //抽象属性    def hello(): Unit   //抽象方法}class Teacher extends Person09{    val name:String = "teacher"    def hello():Unit = {        println("hello teacher")    }}

      2)继承&重写

      (1)如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类

      (2)重写非抽象方法需要用override修饰,重写抽象方法则可以不加override。

      (3)子类中调用父类的方法使用super关键字

      (4)子类对抽象属性进行实现,父类抽象属性可以用var修饰;

      子类对非抽象属性重写,父类非抽象属性只支持val类型,而不支持var。

      因为var修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写

      (5)Scala中属性和方法都是动态绑定,而Java中只有方法为动态绑定。

      6.5.2 匿名子类

      1)说明

      Java一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。

      2)案例实操

      // 定义抽象类abstract class Persion{    var name: String    def eat(): Unit}def main(args:Array[String]): Unit = {    val person:Person = new Persion{        override var name: String = "candy"        override def eat(): Unit = println("eat...")    }    println(person.name)    person.eat()}

      6.6 特质(Trait)

      Scala语言中,采用特质trait(特征)来代替接口的概念,也就是说,多个类具有相同的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字trait声明。

      Scala中的trait中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(mixin)多个特质。这种感觉类似于Java中的抽象类。

      Scala引入trait特征,第一可以替代Java的接口,第二个也是对单继承机制的一种补充。

      6.6.1 特质声明

      1)基本语法

      trait 特质名 {  trait主体}

      6.6.2 特质基本语法

      一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素,所以在使用时,也采用了extends关键字,如果有多个特质或存在父类,那么需要采用with关键字连接。

      1)基本语法

      没有父类:class 类名 extends 特质1 with 特质2 with 特质3 ...

      有父类:class 类名 extends 父类 with 特质2 with 特质3 ...

      2)说明

      (1)类和特质的关系:使用继承的关系。

      (2)当一个类去继承特质时,第一个连接词是extends,后面是with。

      (3)如果一个类在同时继承特质和父类时,应当把父类写在extends后。

      package org.exampleobject Person {  def main(agrs: Array[String]): Unit = {    val student:Student = new Student    student.age = 20    student.say()    student.study    student.dating    student.play    println(student.age)  }}class Person {  val name: String = "person"  var age: Int = 18  def say(): Unit = {    println("hello from " + name )  }}// 定义一个特质trait Young {  // 声明抽象和非抽象属性  var age: Int  val name: String = "young"  // 声明抽象和非抽象方法  def play(): Unit = {    println("young people is playing")  }  def dating(): Unit}class Student extends Person with Young{  // 重写冲突的属性  override val name: String = "student"  // 实现抽象方法  def dating(): Unit = println(s"student $name is dating")  def study(): Unit = println(s"student $name is studing")  // 重写父类方法  override def say(): Unit = {    super.say()    println(s"hello from: student $name")  }}

      6.6.3 特质叠加

      由于一个类可以混入(mixin)多个trait,且trait中可以有具体的属性和方法,若混入的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。冲突分为以下两种:

      第一种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。

      第二种,一个类(Sub)混入的两个trait(TraitA,TraitB)中具有相同的具体方法,且两个trait继承自相同的trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala采用了特质叠加(从右到左)的策略。

      所谓的特质叠加,就是将混入的多个trait中的冲突方法叠加起来,案例如下,

      object Test14_Trait {  def main(args: Array[String]): Unit = {    val myBall = new MyBall()    println(myBall.describe()) //yellow-foot-ball  }}//定义一个父特征trait Ball {  def describe(): String = "ball"}//定义子特征trait Color extends Ball {  var color: String = "yellow"  override def describe(): String = color + "-" + super.describe()}trait Category extends Ball {  var category: String = "foot"  override def describe(): String = category + "-" + super.describe()}//定义子类,继承两种特征class MyBall extends Category with Color {  override def describe(): String = "my ball is a" + super.describe()}

      结果如下:

      6.6.4 特质叠加执行顺序(从右到左按顺序叠加)

      当一个类混入多个特质的时候,scala会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的super.describe()调用的实际上是排好序后的下一个特质中的describe()方法。,排序规则如下:

      6.6.5特质和抽象类的区别

      1)优先使用特质。一个类扩展多个特质是很方便的,但却只能扩展一个抽象类。

      2)如果你需要构造函数参数,使用抽象类。因为抽象类可以定义带参数的构造函数,而特质不行(有无参构造)。

      6.6.6 动态混入特质

      在Java中,当一个类定义之后,没有继承的接口不可以实现。而在sacla中,可以动态混入特质,如下:

      // 1. 父类-抽象类abstract class Car {  def brand:String  def engine:String  def laba():Unit = {    println("鸣笛")  }}// 2. 定义子类,继承Car父类,实现父类抽象方法class LingYun extends Car{  override def brand: String = {    println("凌云")    "凌云骑车"  }  override def engine: String = {    println("纯电动汽车")    "电动车"  }}// 3. 定义特质trait Balance {  def balance:String}trait FlyAndSea {  def fly={    println("冲上云霄")  }  def downSea():Unit}// 4. 实例化对象object TestCar{  def main(args: Array[String]): Unit = {    // 动态混入特性,{ 花括号内重写方法 }    val lingyun:LingYun with Balance with FlyAndSea =         new LingYun with Balance with FlyAndSea{      override def balance: String = {         println("空气悬挂")        "空气悬挂"       }      override def downSea(): Unit = { println("下还") }    }  }}

      七、模式匹配match

      Scala中的模式匹配类似于Java中的switch语法,但scala从语法中补充了更多的功能。

      7.1 基本语法

      模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _分支,类似于Java中default语句。

      1)说明

      (1)如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句,若此时没有case _ 分支,那么会抛出MatchError。

      (2)每个case中,不需要使用break语句,自动中断case。

      (3)match case语句可以匹配任何类型,而不只是字面量。

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

      // 模式匹配  def match1(x:Int):String={    x match {      case 1 => "one"      case 2 => "two"      case _ => "many"    }  }  println("match1=>"+match1(1))    // match1 => one

      2)案例实操:用匹配模式实现简单的二元运算

        def matchs(a:Int,b:Int)(op:Char):Int = {    op match{      case '+' => a+b      case '-' => a-b      case '*' => a*b      case '/' => a/b      case _   -> -1    }   }  println(matchs(3,2)('*'))

      7.2 模式守卫

      1)说明

      如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫。

      2)案例实操:

      // "A" 优秀 "B"良好 "C"合格 "D"不合格  "韩梅梅" 特殊学生  def match4(name:String,score:String):Unit={    score match {      case "A" => println(name + "优秀")      case "B" => println(name + "良好")      case "C" => println(name + "合格")      case _ if name=="韩梅梅" => println("特殊学生")      case _ => println(name + "不合格")    }  }

      7.3 模式匹配类型

      7.3.1 匹配常量

      1)说明

      Scala中,模式匹配可以匹配所有的字面量,包括字符串,字符,数字,布尔值等等。

      2)实操

        def defcribeConst(x:Any):String=x match {    case 1 => "Int one"    case "hello" => "String hello"    case true => "Boolean true"    case '+' => "Char +"    case _ => "else"                // _ 下划线为占位符,也可以换成其他符号  }  println(defcribeConst(2.3))

      7.3.2 匹配类型

      注意:

      (1)我们在底层操作的时候,JVM有“泛型擦除”,判断底层类型的时候,只能判断出是一个List类型,而List里面的泛型会被擦除。所以不管List里面的泛型是Int还是String,都是List,所以能够直接匹配成功。但Array没有泛型擦除。

      (2)_表示占位符,当数组中有多个元素时,用 _* 表示多个元素的占位符

        def defcribeType(x:Any):String=x match {    case i:Int => "Int " + i    case s:String => "String "+s    case list:List[String] => "List "+list.mkString("-")    case _ => "something else"  }  println(defcribeType(List(1,3,2,4)))    // List 1-3-2-4  println(defcribeType(2.3))               // something else

      7.3.3 匹配数组

      1)说明

      scala模式匹配可以对集合进行精确的匹配,例如匹配只有两个元素的、且第一个元素为0的数组。

      2)案例实操

        def match5(arr:Array[String]):Unit={    arr match {      case Array("jack") => println("hello jack")      case Array(str1,str2) => println(str1,str2)      case Array("aaa",_*) => println("多元素数组")      case Array(s1,s2,"nancy",_*) => println("第三个元素是nancy的数组")      case Array(_,_,"bob",_*) => println("第三个元素是bob的数组",arr.mkString("-"))      case _ => println("who are u")    }  }

      7.3.4 匹配列表

      1)说明

      匹配列表与匹配数组类似。

      2)案例实操

        def defcribeList(list:List[String]) = {    list match {      case List("1") => println(1)      case List("acdc",_) =>println("acdc开头的list")      case List(l1,l2) => println(l1+","+l2)      case _ => println("其他")    }  }  defcribeList(List("acdb","1"))        // acdc开头的list

      7.3.5 匹配对象、样例类case

      1)匹配对象的方式

      (1)定义类

      (2)定义伴生对象

      (3)实现apply方法、实现unapply方法,用来对对象属性进行拆解

      上面这种方法尽管实现了匹配对象的功能,但是过于复杂。于是引入了样例类 case的概念。

      样例类的定义只需要在类的前面加关键字case。默认定义了伴生对象,并实现了apply、unapply方法

      object FunctionDemo {  // 定义样例类  case class Teacher(name:String, age:Int)  def match(teacher:Teacher):Unit={    teacher match {      case Teacher("gree", 39) => println("hello gree teacher")      case Teacher("burlin", 18) => println("hello burlin")      case Teacher(name, age) if name=="李伟" => println("大神")      case x:Teacher => println("hello "+x.name)    }  }  match3(Teacher("gree",39))    // hello gree teacher  match3(Teacher("gree",40))    // hello gree,age不符合}

      八、隐式转换

      当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用于将类型进行转换,实现二次编译。

      8.1 隐式函数

      1)说明

      scala一切皆对象,通过toXxx的方法进行类型转换。但是当对象数量较多的时候,挨个调用方法进行转换,会大量增加代码量。于是引入了隐式转换的概念。

      隐式转换可以在不需改任何代码的情况下,扩展某个类的功能。

      // 当传入参数和输出参数不匹配时,运行时会报错val a:Int = "1"val s:String = 10// scala一切皆对象,通过toInt方法进行转换。val a:Int = "1".toIntval s:String = 10.toString

      2)案例实操

      需求:通过隐式转化为Int类型增加方法。

      // 使用implicit关键字声明的函数称之为隐式函数// 当想调用对象功能时,如果编译错误,那么编译器会尝试在当前作用域范围内查找能调用相应功能的转换规则// 这个调用过程是由编译器完成的,所以称之为隐式转换,也叫自动转换implicit def stringToInt(value:String):Int=Integer.parseInt(value)implicit def intToString(value:Int):String=value.toStringval a:Int = "1"val s:String = 10

      8.2 隐式参数

      普通方法或者函数中的参数可以通过implicit关键字声明为隐式参数,调用该方法时,就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。

      1)说明

      (1)同一个作用域中,相同类型的隐式值只能有一个

      (2)编译器按照隐式参数的类型去寻找对应类型的隐式值,与隐式值的名称无关。

      (3)隐式参数优先于默认参数

      2)案例实操

      // 定义sum函数  def sum(a:Int)(b:Int,name:String):Int={    println(name)    a + b  }  println(sum(10)(20,"张三"))// 定义隐式参数  implicit val num1:Int = 11        // 与参数名无关,与类型有关  implicit val name:String = "张三"  def sum2(a:Int)(implicit name:String, b:Int):Int={    println("sum2="+name)    a + b  }  println(sum2(10))               // sum2=张三,21// 对隐式参数重新赋值  println(sum2(10)("李四",13))    // sum2=李四,23

      8.2.3 优先级比较

      方法传值 >> 隐式传值 >> 默认值

      // 1. 隐式值  implicit val num1:Int = 11  implicit val name:String = "张三"// 2. 方法传值 > 隐式值  def sum(a:Int)(b:Int,name:String):Int={    println(name)    a + b  }  println(sum(10)("李四",13))        // sum2=李四,23// 3.默认值   

      应用:

      如下代码,输入的类型为Double,输出类型为String,会调用隐式函数,完成+500的操作。和输入输出的类型有关。

      // 传入一个double的数,+500后以String类型输出implicit def doubleFun(value:Double):String={(value+500).toString}val d:String = 23.0println(d)                // 输出523.0

      8.3 隐式类

      在Scala2.10后提供了隐式类,可以使用implicit声明类,隐式类的非常强大,同样可以扩展类的功能,在集合中隐式类会发挥重要的作用。

      1)隐式类说明

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

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

      Object Test_Implicit {  def main(args: Array[String]):Unit = {// 需要比较两数大小的时候new一个函数。// 缺点:不通用,每来一个整数都需要new一个对象    val newInt = new MyInt(12)    println(newInt.myMas(15))  }}// 自定义类class MyInt(val self: Int) {  // 自定义比较大小方法  def myMax(n:Int):Int = if(n  self) self else n}

      2)案例实操

      Object Test_Implicit {  // 1. 隐式类  implicit class MyInt2(val self: Int){    // 自定义比较大小方法    def myMax(n:Int):Int = if(n  self) self else n  }  println(12,myMax(15))}

      九、泛型

      9.1 协变和逆变

      1)语法

      class MyList[ +T ]{ //协变 } class MyList[ -T ]{ //逆变 }class MyList[ T ] //不变

      2)说明

      协变:Son是Father的子类,则MyList[Son] 也作为MyList[Father]的“子类”。

      逆变:Son是Father的子类,则MyList[Son]作为MyList[Father]的“父类”。

      不变:Son是Father的子类,则MyList[Father]与MyList[Son]“无父子关系”。

      3)实操

      object Test_Generics {  def main(args: Array[String]): Unit = {    // 1. 协变和逆变    val child: Child = new Child    val childList:MyCollection1[Parent] = new MyCollection1[Child]    val childList:MyCollection1[SubChild] = new MyCollection1[Child]    // 2. 上下限    def test[A 

上一篇:揭秘,你不知道的柙字读音与深义

下一篇:最佳搭档服务器怎么设置?