Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的 静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。
Scala 注释使用和 Java 完全一样。
单行注释://
多行注释:/**/
文档注释:/*
*
*/
常量:用val声明 val 常量名 [:常量类型]=初始值
变量:用var声明 var 变量名 [:变量类型]=初始值
注意:



字符类型可以表示单个字符,字符类型是 Char。
布尔类型也叫 Boolean 类型,Booolean 类型数据只允许取值 true 和 false。Boolean 类型占 1 个字节。

自动转换(隐士转换):精度小的自动向精度大的转换
强制类型转换:调用toXxx()方法

对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整 数部分而舍弃小数部分。
对一个数取模 a%b,和 Java 的取模规则一样。

==与equals
java: ==比较两个变量本身的值,即两个对象在内存中的首地址;equals 比较字符串中所包含的内容是否相同。
scala:==更加类似于 Java 中的 equals



if(条件表达式){
执行代码块
}[else if(条件表达式){
执行代码块
}][else{
执行代码块
}]
object s03 {
def main(args: Array[String]): Unit = {
println("input age")
var age=StdIn.readInt()
if(age<18){
println("童年")
}else if(age>=18&&age<30){
println("中年")
}else{
println("老年")
}
}
}
Scala 中 if else 表达式其实是有返回值的,具体返回值取决于满足条件的 代码体的最后一行内容。
val res:String=if(age<18){
"童年"
}else if(age>=18&&age<30){
"中年"
}else{
"老年"
}
println(res)
Scala 中返回值类型不一致,取它们共同的祖先类型。
val res:Any=if(age<18){
"童年"
}else if(age>=18&&age<30){
"中年"
}else{
100
}
println(res)
Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称 为 for 推导式或 for 表达式。
for(变量<-a to b by c){//[a,b] 步长为 c
todo
}
for(变量 <-a until b by c){//[a,b) 步长c
todo
}
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环 体内部,为 false 则跳过,类似于 continue。
for(变量 <-a to b if 关于变量的条件语句){
todo
}
val res = for(i <- 1 to 10) yield i
println(res)
将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。
与java相同
Scala 语言是一个完全面向对象编程语言。万物皆对象
对象的本质:对数据和行为的一个封装
Scala 语言是一个完全函数式编程语言。万物皆函数。
函数的本质:函数可以当做一个值进行传递

方法有访问权限,函数没有访问权限
为完成某一功能的程序语句的集合,称为函数。
类中的函数称之方法。
函数没有重载和重写的概念;方法可以进行重载和重写
Scala 中函数可以嵌套定义
函数至简原则:能省则省
- 函数可以作为值进行传递
- 函数可以作为参数进行传递
- 函数可以作为函数返回值返回
没有名字的函数就是匿名函数。
(x:Int)=>{函数体}
x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑
传递匿名函数至简原则:
如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包。
object TestFunction {
def main(args: Array[String]): Unit = {
def f1()={
var a:Int = 10
def f2(b:Int)={
a + b
}
f2 _
}
// 在调用时,f1 函数执行完毕后,局部变量 a 应该随着栈空间释放掉
val f = f1()
// 但是在此处,变量 a 其实并没有释放,而是包含在了 f2 函数的内部,形成了闭合的效果
println(f(3))
println(f1()(3))
// 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存
在闭包
def f3()(b:Int)={
a + b
}
println(f3()(3))
}
}
函数柯里化:把一个参数列表的多个参数,变成多个参数列表。
当函数被调用是先执行被调函数里的语句。
当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。
def main(args: Array[String]): Unit = {
lazy val res = sum(10, 30)
println("----------------")
println("res=" + res)//只有res调用sum函数才执行
}
def sum(n1: Int, n2: Int): Int = {
println("sum 被执行。。。")//只有res调用该语句才输出
return n1 + n2
}
azy 不能修饰 var 类型的变量
[修饰符]class 类名{
类体
}
Scala 语法中,类并不声明为 public,所有这些类都具有公有可见性(即默认就是 public)
一个scala源文件可以包含多个类
val | var 对象名[:类型]=new 类型()
val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。
var 修饰对象,可以修改对象的引用和修改对象的属性值
自动推导变量类型不能多态,所以多态需要显示声明
Scala 类的构造器包括:主构造器和辅助构造器
class 类名(形参列表){//主构造器
def this(形参列表){//辅助构造器
}
}
辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分。
辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。
构造器调用其他另外的构造器,要求被调用构造器必须提前声明。
Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰
class Person(nameParam: String) {
var name = nameParam
var age: Int = _
def this(nameParam: String, ageParam: Int) {
this(nameParam)
this.age = ageParam
println("父类辅助构造器")
}
println("父类主构造器")
}
class Emp(nameParam: String, ageParam: Int) extends
Person(nameParam, ageParam) {
var empNo: Int = _
def this(nameParam: String, ageParam: Int, empNoParam: Int) {
this(nameParam, ageParam)
this.empNo = empNoParam
println("子类的辅助构造器")
}
println("子类主构造器")
}
object Test {
def main(args: Array[String]): Unit = {
new Emp("z3", 11,1001)
}
}
Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同 的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。
Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可 以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。
Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种 补充。
一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素, 所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with 关键字连接。
没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …
有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3…
说明 :
由于一个类可以混入(mixin)多个 trait,且 trait 中可以有具体的属性和方法,若混入 的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。 冲突分为以下两种:
第一种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且 两个 trait 之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。
第二种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且 两个 trait 继承自相同的 trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala 采用了特质叠加的策略。
所谓的特质叠加,就是将混入的多个 trait 中的冲突方法叠加起来
trait Ball {
def describe(): String = {
"ball"
}
}
trait Color extends Ball {
override def describe(): String = {
"blue-" + super.describe()
}
}
trait Category extends Ball {
override def describe(): String = {
"foot-" + super.describe()
}
}
class MyBall extends Category with Color {
override def describe(): String = {
"my ball is a " + super.describe()
}
}
object TestTrait {
def main(args: Array[String]): Unit = {
println(new MyBall().describe())
}
}
//结果:my ball is a blue-foot-ball
上述案例中的 super.describe()调用的是父 trait 中的方法吗?
案例中的 super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质, 即,MyClass 中的 super 指代 Color,Color 中的 super 指代 Category,Category 中的 super 指代 Ball。
如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如 super[Category].describe()。