scala面试题总结
一、scala语言有什么特点?什么是函数式编程?有什么优点?
1、scala语言集成面向对象和函数式编程
2、函数式编程是一种典范,将电脑的运算视作是函数的运算。
3、与过程化编程相比,函数式编程里的函数计算可以随时调用。
4、函数式编程中,函数是一等功明。
二、scala中的闭包
1、定义:你可以在任何作用域内定义函数:包,类甚至是另一个函数或方法。在函数体内,可以访问到相应作用域内地任何变量。(重点)函数可以在变量不再处于作用域内时被调用。
例如:
def mulBy(factor:Double) = (x:Double) => factor * x
//开始调用
val tripe = mulBy(3)
val half = mulBy(0.5)
println(tripe(14) + " " + half(14))
这就是一个闭包
三、scala中的柯里化
定义:柯里化指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有的第二个参数作为参数的函数
例如:
def mul(x:Int,y:Int) = x * y //该函数接受两个参数
def mulOneAtTime(x:Int) = (y:Int) => x * y //该函数接受一个参数生成另外一个接受单个参数的函数
这样的话,如果需要计算两个数的乘积的话只需要调用:
mulOneAtTime(5)(4)
这就是函数的柯里化
四、scala中的模式匹配
scala的模式匹配包括了一系列的备选项,每个替代项以关键字大小写为单位,每个替代方案包括一个模式或多个表达式,如果匹配将会进行计算,箭头符号=>将模式与表达式分离
例如:
obj match{
case 1 => "one"
case 2 => "two"
case 3 => "three"
case _ => default
}
五、case class和class的区别
case class:
是一个样本类,样本类是一种不可变切可分解类的语法糖,也就是说在构建的时候会自动生成一些语法糖,具有以下几个特点:
1、自动添加与类名一致的构造函数(也就是半生对象,通过apply方法实现),也就是说在构造对象的时候不需要使用new关键字
2、样本类中的参数默认是val关键字,不可以修改
3、默认实现了toString,equals,hashcode,copy方法
4、样本类可以通过==来比较两个对象,不在构造方法内地二属性不会用在比较上
class:
class是一个类
1、class在构造对象的时候需要使用new关键字才可以。
六、谈谈scala中的隐式转换
所谓的隐式转换函数(implicit conversion function)指的事那种以implicit关键字申明的带有单个参数的函数,这样的函数会被自动的应用,将值从一种类型转换为另一种类型
比如:需要把整数n转换成分数n/1
implicit def int2Fraction(n:Int) = Fraction(n,1)
这样就可以做如下表达式求职:
val result = 3 * Fraction(4,5)
此时,隐士转换函数将整数3转换成一个Fraction对象,这个对象接着又被乘以Fraction(4,5)
七、scala中的伴生类和伴生对象是怎么一回事
在scala中,单例对象与类同名时,该对象被称为该类的伴生对象,该类被称为该对象的伴生类。
伴生类和伴生对象要处在同一个源文件中
伴生对象和伴生类可以互相访问其私有成员
不与伴生类同名的对象称之为孤立对象
八、scala和java 的区别
1、变量申明:
scala:只需要申明是val或是var,具体的类型(比如String,Int,Double等等),由编译器自行推断
java: 需要在变量前面先注明变量的类型
2、返回值:
scala:申明返回值是在后面,并且不需要return语句,非要用,也不是不可以
java: 如果有返回值,需要return语句
3、结束符
scala:不需要使用分号作为结束符
java: 每个语句结束后需要分号作为结束符
4、循环
scala:循环语句可以用于守卫
java: 不可以这么写
5、通配符:
scala:_
java: *
6、构造器
scala:构造器名称为this,scala的辅助构造器之前需要有一个主构造器或者其他辅助构造器,并且scala的构造器参数可以直接放在类的后面
java: 构造器名称需要与类名称一样
7、内部类
scala:scala实例化的内部类是不同的,可以使用类型投影,例如 Network#Person表示Network的Person类
java:内部类从属于外部类
8、接口
scala:scala中接口称为特质(trait),特质中是可以写抽象方法,也可以写具体的方法体以及状态。且类是可以实现多个特质的。
特质中未被实现的方法默认就是抽象的
子类的实现或继承统一使用的事extends关键字,如果需要实现或继承多个使用with关键字
特质中可以有构造器
特质可以继承普通的类,并且这个类称为所有继承trait的父类
java: java中的接口(interface),接口中的方法只能是抽象方法,不可以写具体包含方法体的方法
接口中不能有抽象的属性,且属性的修饰符都是public static final
类实现接口需要使用implements关键字,实现多个接口,需要用逗号隔开
接口中不可以有构造器
接口不可以继承普通的类
9、赋值
scala:scala中的赋值语句返回结果是unit的不可以串联,例如x=y=1,这样是有问题的,x并没有被赋值为1
java: x=y=1,这样是没问题的
九、谈谈scala的尾递归
正常得递归,每一次递归步骤,需要保存信息到堆栈中去,当递归步骤很多的时候,就会导致内存溢出
而尾递归,就是为了解决上述的问题,在尾递归中所有的计算都是在递归之前调用,编译器可以利用这个属性避免堆栈错误,尾递归的调用可以使信息不插入堆栈,从而优化尾递归
例如:
正常递归:
def sum(n:Int):Int = {
if (n == 0){
n
}else{
n + sum(n - 1)
}
}
//执行结果
sum(5)
5 + sum(4) // 暂停计算 => 需要添加信息到堆栈
5 + (4 + sum(3))
5 + (4 + (3 + sum(2)))
5 + (4 + (3 + (2 + sum(1))))
5 + (4 + (3 + (2 + 1)))
15
尾递归
@tailrec //告诉编译器,强制使用尾递归
def tailSum(n:Int,acc:Int = 0):Int = {
if (n ==0 ){
acc
}else{
tailSum(n - 1,acc + n)
}
}
//执行结果
tailSum(5) // tailSum(5, 0) 默认值是0
tailSum(4, 5) // 不需要暂停计算
tailSum(3, 9)
tailSum(2, 12)
tailSum(1, 14)
tailSum(0, 15)
15