Scala基本认知
Scala是一种Java虚拟机(JVM)上的编程语言,它结合了面向对象编程和函数式编程的最佳特性。
Scala具有静态类型系统和类型推断功能,这使得编写代码变得更加简明和紧凑。
Hello Scala
//ovject:声明一个单例对象(伴生对象) object Test { //Unit相当于Java的void,Array是Scala的一个集合类型,中括号[]代表泛型 def main(args: Array[String]): Unit = { println("hello Scala") sayHello() //可以直接使用Java的System来打印输出 System.out.println("hello Java") } def sayHello(): Unit = { println("hello Scala") } }
方法的定义
def 函数名(参数名 : 参数类型) : 返回值类型 = { //函数体 }
伴生对象
相比较Java,Scala是一门完全面向对象的语言;这是因为Java的设计之处存在一些不是面向对象的地方。我们面向对象,要求我们的任何行为(方法)都必须从对象出发,但Java往往并没有这么做,比如:通过类名调用静态方法、静态变量等。
在Scala中,被 class修饰的叫类,被 object修饰的叫伴生对象。只要是伴生对象中的变量和方法,就相当于Java中被static修饰了,可以通过 类名.变量名/函数名 来获得。
在Scala中,类和伴生对象必须拥有相同的名称,它们之间的关系是一对一的,彼此之间可以访问对方的私有成员。伴生对象中的方法和属性可以被视为对类的补充,通常用于实现工厂模式等场景,并且在调用时可以直接使用伴生对象的名称,无需实例化类。
我们以一个Student类为例:
Java:
public class Student { private String name; private int age; private static String school = "xx大学"; public Student(String name, int age) { this.name = name; this.age = age; } public void printInfo(){ System.out.println(this.name + " " + this.age + " " + Student.school); } public static void main(String[] args) { Student student1 = new Student("Bob",18); Student student2 = new Student("Tom",18); student1.printInfo(); student2.printInfo(); } }
Scala:
- Scala在声明一个类的时候,直接就把属性都定义好了,所以Scala都不需要构造方法。我们通过伴生对象来获取所有Student类的公有变量school。
- Scala的类和伴生类名字必须相同并且在同一文件内!
- class 类内不能运行main方法,只能在单例(伴生类)中执行main方法!
import chapter01.Student.school class Student(name: String,age: Int) { def printInfo(): Unit = { //不需要this 因为这就是一个对象 println(name+" "+age+" "+school) } } //引入伴生对象 object Student{ val school: String = "xx大学"; def main(args: Array[String]): Unit = { val stu = new Student("李大喜", 25) stu.printInfo() } }
2、变量和数据类型
2.1、注释
Scala的注释和Java完全相同。
2.2、变量和常量
Java中的变量和常量
- 变量: 变量类型 变量名 = 初始值 int age = 10
- 常量: 常量类型 变量名 = 初始值 final int VALUE = 10
Scala基本语法
- var 变量名[: 变量类型] = 初始值 var age: Int = 10
- val 常量名[: 常量类型] = 初始值 val VALUE: Int = 10
通常,我们能用常量就不用变量(函数式编程的思想)。Scala的变量类型可以省略。
- Scala中,类型确定后不可修改,说明Scala是强语言类型。
- Scala在声明变量时必须有初始值。
object Test { def main(args: Array[String]): Unit = { //声明变量的通用语法 var a: Int = 10 var name: String = "Tom" //1.声明变量可以忽略类型 var b = 10 val c = 10 }
- 被常量符 val 修饰的类不可以修改(只是说这个类的不能被复制,并不是说不能修改它的属性),但是如果这个类的属性是被 var 修饰,那么它的属性是可以修改的。
var stu = new Student("alice",20) stu = new Student("Alice",20) val stu2 = new Student("Bob",20) stu2.age = 21 //stu2 = stu //这样不行的
- 我们可以在声明类(class)的时候来指定属性是常量还是变量
//name可以通过对象修改,age不可被修改 class Studnt(name: String,val age: Int){ }
2.3、标识符
标识符就是我们的变量名、函数名,也就是说,只要是我们可以自己起名字的地方,都是标识符。Scala中的标识符规则基本与Java一致。但有自己不一样的地方:
- 可以以操作符(+ - * / # !)作为标识符,但是必须只包含操作符。
- 可以使用关键字,但需要用反引号 `` 包起来
var +-*/ = "hello" println(+-*/) val `if` = "hi" println(`if`)
2.4、字符串
字符串的用法我越看越像 Python
基本语法
- 通过+拼接
- printf格式化:可通过%传值
- 字符串模版:可通过$获取字符串值(类似于shell脚本中的${},可以省去花括号{}),一般我们为了将变量区分开来都会加花括号
- 原格式输出:"""文本"""(使用三引号包起来)
object Test02 { def main(args: Array[String]): Unit = { //+拼接 println("神探狄仁杰 "+"李元芳") //%d 整型, %s 字符串类型 val age = 58 val name = "李元芳" printf("不死战神%s今年%d岁了",name,age) //输出三个 李元芳 println(name*3) //李元芳今年58岁了 println(s"${name}今年${age}了") //输出小数 %2.2f 的意思是整个数的长度不够2就补空格,小数后面保留两位 val value: Double = 2.345 println(f"${value}%2.2f") //输出多行并保持原格式输出 val sql = s""" |select * |from | student |where | name = ${name} |and | age > ${age} |""".stripMargin println(sql) } }
2.5、标准输入输出
基本语法
StdIn.readLine、StdIn.readInt、StdIn.readDouble、StdIn.readFloat...
import scala.io.StdIn //... //输入 val name = StdIn.readLine() val age = StdIn.readInr() //输出 println(s"姓名:${name} 年龄:${age}")
2.6、文件的读写
读取文件十分简单,就像Python那样容易,直接导入 scala.io.Source。
但是写入文件Scala并没有提供相关的API,因为我们的Java已经提供了,而我们Scala又可以直接使用Java的API。
import java.io.{File, PrintWriter} import scala.io.Source object Test04_io { def main(args: Array[String]): Unit = { //1.从文件中读取数据 foreach是函数式编程的内容,意思是传入一个函数将文本顺便打印出来 //从项目路径下读取文件 默认当前路径是idea的当前项目路径最顶层 Source.fromFile("src/main/resources/test_read.txt","utf-8").foreach(print) //2.将数据写入文件 val writer = new PrintWriter(new File("src/main/resources/test_write.txt")) val content = """hello spark |hello java |hello scala |""".stripMargin writer.write(content) writer.close() } }
2.7、数据类型(重点)
Java八大数据类型 :byte、short、int、long、float、double、boolean、char。
Scala中数据类型分为两大类:数值类型(AnyVal)、 引用类型(AnyRef),不管是值类型还是引用类型都是对象。
1、整型(Byte、Short、Int、Long)
- Byte:-128~127
- Short:-32768~32767(三万二左右)
- Int:-2147483648~2147483647(二十一亿左右)
- Long:-9223372036854775808~-9223372036854775807(超级大)
Scala中默认的整数类型为 Int,所以默认定义一个Long类型需要在数值后+ L。
Scala中默认的浮点数类型为 Double,所以默认定义一个Float类型需要在数值后+ F。
val a1: Byte = 10 val a2: Byte = -128 val a3: Byte = 10+10 //强制转换 val a4: Byte = (a1 + 10).toByte //short 3万2左右 val b1: Short = 32000 val b2: Short = 32767 //int 21亿 val c1: Int = 2100000000 //几乎无穷大 val d1: Long = 123456789123456L //浮点数 val f1: Float = 1.2345F
2、字符类型(Char)
基本用法和Java一致
1、字符和ASCII码的相互转化
val word: Char = 'a' val ascii: Int = word println(s"${word}的ASCII码为 "+ascii) val asc: Int = 98 val wo: Char = asc.toChar println(s"ASCII码${asc}对应的字符为 "+wo)
3、布尔类型
boolean 类型占 1 个字节,用法和Java一致。
val isTrue: Boolean = 1==1 println(isTrue) //true
4、Unit、Null类型和Nothing类型
- Unit:表示空值,函数返回值为空,相当于 void。Unit只有一个实例,写作 () 。
- Null:表示空引用,Null类型只有一个实例 null,数值类型不可以复制为 null,引用类型才可以。
- Nothing:Nothing 类型在 Scala 的类层级最低端;它是任何其他类型的子类型。 当一个函数,我们确定没有正常的返回值,可以用 Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性)。
def say_hello(name: String): Unit = { println(f"hello ${name}!") } def method(n: Int): Nothing ={ throw new NullPointerException } //Unit //输出方法的结果 val res = say_hello("tom") println(res) //输出 () //这里要用 var 因为我们要对变量重新赋值 //数值类型不可以复制为 null,只有引用类型才能被复赋值为 null // var k = 10 // k=null // println(k) val aa: Null = null println(aa) //null var student: Student = new Student("alice",19) student = null println(student) //null
5、类型转换
5.1、自动类型转换
Java 数据类型自动转换:
- byte -> short -> int
- char -> int
Scala 数据类型自动转换:
//低精度->高精度 自动转换 val bb: Byte = 10 val cc: Short = bb println(cc) //10 //高精度->低精度 强制转换 val dd: Byte = cc.toByte println(dd) //10
5.2、强制类型转换
//高精度->低精度 强制转换 var num1: Int = 2.5.toInt var num2: Int = 2.9.toInt //取整是取整数部分 print(num) //2 print(num) //-2
5.3、数值类型和String类型的转换
//数值->String val s:String = 1.5+"" //String->数值 val m: Int = "12".toInt val f: Int = "12.3".toFloat.toInt //小数字符串不能直接转Int,要先转浮点数
6、数据溢出
Byte能表示-128~127,我们把Int类型的130强制转换为Byte:
val num: Int = 130 val res: Byte = num.toByte println(res) //输出-126 /** * 130: Int类型,32位,4个字节 * 原码: 0000 0000 1000 0010 * 补码: 0000 0000 1000 0010 * * 截取最后一个字节做强转 * 得到补码 1000 0010 * 对应原码 1111 1110 符号位不变,其余取反+1 * -126 类推 131 -> -125,132 -> -124 */