Scala学习补充篇
Posted Mr.zhou_Zxy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala学习补充篇相关的知识,希望对你有一定的参考价值。
一 主构造器和辅助构造器
1 构造器介绍
和Java一样,scala构造对象也需要调用构造方法,并且可以右任意多个构造方法(即Scala中构造器也支持重载)
Scala构造器包括主构造器和辅助构造器
2 构造器基本语法
class 类名(形参列表) { // 主构造器 注意这种定义格式和java不同
// 类体
def this(形参列表) { // 辅助构造器
}
def this(形参列表) { //辅助构造器可以有多个...
}
}
3 注意事项
1.scala构造器作用是完成对新对象的初始化,构造器没有返回值
2.主构造器的声明直接放置于类名之后
3.主构造器会执行类定义中的多有语句(方法除外),这里可以体会到Scala的函数式编程和面向对象编程融合在一起,即:构造器也是方法(函数),传递参数和使用方法和前面的函数部分内容没有区别
4.如果主构造器无参数,小括号可以省略,构建对象时调用的构造方法的小括号也可以省略
5.辅助构造器名称为this(这个this和Java不一样),多个辅助器通过不同的参数列表进行区分,在底层就是构造器重载
6.如果想让主构造器编程私有的,可以在()之前加上private,这样用户只能通过辅助构造器来构造对象
7.辅助构造器的声明不能和主构造器的声明一致,会发生错误
8.辅助构造器的第一行有一定要调用主构造器或者其他辅助构造器
4 案例说明
lass People{
@BeanProperty var name:String = _
@BeanProperty var age:Int = _
println("主构造器")
//辅助构造器的第一行必须调用其他的构造器
def this(name:String,age:Int){
this()//调用主构造器
this.name = name
this.age = age
println("辅助构造器1")
}
def this(name:String){
this(name,0)//调用辅助构造器
println("辅助构造器2")
}
}
二 Final修饰类
object FinalCode1 {
final class people {
def A(): Unit = {
println("zxy")
}
}
class B extends people {
//这里就是报错
}
}
object FinalCode2 {
class people {
def A(): Unit = {
println("zxy")
}
}
class B extends people {
//这里就是编译成功
}
}
三 apply方法和unapply方法
1 apply方法
当Scala中类或者对象有一个主要的用途的时候,apply方法就是一个很好的语法糖
- 举例:
class Foo(foo:String){
}
object Foo{
def apply(foo:String):Foo={
new Foo(foo)
}
}
定义一个Foo类,并且在这个类中,有一个伴生对象Foo,里面定义一个apply方法。有了这个apply方法后,我们在调用这个Foo类的时候,用函数的方式来调用:
object Client{
def main(args:Array[String]):Unit = {
val foo = Foo("Hello")
}
}
我们用Foo("Hello)的方法,就得到一个Foo类型的对象,这一切就是apply的功劳,如果没有apply方法,我们将需要使用new关键字来得到Foo对象
2 apply方法做工厂
apply方法最佳的实践方式之一就是用来做工厂,比如在Scala的标准库中,许多集合类给我们提供了apply方法来创建集合:
类型1:
object num{
def main(args:Array[String]):Unit = {
val arr = new Arrray[Int](3)
arr(0) = 1
arr(1) = 2
arr(2) = 3
arr.foreach(x => print(x + " "))
println()
}
}
类型2:
object num{
def main(args:Array[String]):Unit = {
val arr = Array(1,2,3)
arr.foreach(x => print(x + " "))
println()
}
}
类型1和类型2都是用来创建Array。
第一种方式是使用new关键字,这是传统的面向对象的方式。
第二种方式呢?我们可以点Array查看一下底层源码,会发现其底层源码中会有一个apply方法
val array = Array("1","2","3")
后台代码有apply支持:
implicit def canBuildFrom[T](implicit t: ClassTag[T]): CanBuildFrom[Array[_], T, Array[T]] =
new CanBuildFrom[Array[_], T, Array[T]] {
def apply(from: Array[_]) = ArrayBuilder.make[T]()(t)
def apply() = ArrayBuilder.make[T]()(t)
}
3 unapply方法
从上面的例子发现,apply其实是有点类似于Java中的构造方法,接受构造参数变成一个对象。
而unapply是接受一个对象,从对象中提取出相应的值。
unapply主要适用于模式匹配
package day05
object Demo5 {
def main(args: Array[String]): Unit = {
testunapply()
}
//测试端口实现
def testunapply() = {
val money = Money(10.1,"RMB")
money match {
case Money(num,"RMB") => println("RMB:" + num)
case _ => println("Not RMB!")
}
}
//伴生类
class Money(val value:Double,val country:String){}
//伴生对象
object Money{
//接受构造参数并变成一个对象
def apply(value: Double, country: String): Money = new Money(value, country)
//接受一个对象,从中提取出相应的值
def unapply(money: Money): Option[(Double, String)] = {
if(money == null){
None
}else{
Some(money.value,money.country)
}
}
}
}
四 abstract抽象类
在Scala中可以定义一个抽象类,抽象类可以定义一些方法,但是不需要实现他们。相反,继承抽象类的子类需要实现这些方法,抽象类是不能被实例化
类型1:非抽象对象,定义方法需要实现
class Element{
def contends:Array[String] = _
}
类型2:抽象方法,定义方法可以不实现,但是其子类必须实现该方法
abstract class Element{
def contends:Array[String]
}
class A extends Element{
override def contends: Array[String] = _
}
五 Nothing -> AnyRef -> AnyVal -> Any
1.Any是abstract类,他是Scala类继承结构中最底层的。所有运行环境中的Scala类都是直接或者间接继承来自Any的类,他就是其他语言中的Object
2.Nothing是所有类的子类,Nothing没有对象,但是可以用来定义类型,例如:抛出异常,则不论该方法应该返回哪种类型,异常的返回值是Nothing
3.AnyRef是所有应用类型的基类
4.AnyVal是所有值类的基类
六 正则表达式
符号 | 含义 |
---|---|
. | 匹配任何字符(\\n除外) |
^ | 匹配字符串起始部分 |
$ | 匹配字符串终止部分 |
* | 匹配0次或者多次前面出现的正则表达式 |
+ | 匹配1次或者多次前面出现的正则表达式 |
? | 匹配0次或者1次前面出现的正则表达式 |
{N} | 匹配N次前面出现的正则表达式 |
{M,N} | 匹配M~N次前面出现的正则表达式 |
\\d | 匹配任何十进制数字 |
\\w | 匹配任何字母数字字符 |
\\s | 匹配任何空格字符 |
\\b | 匹配任何单词边界 |
\\N | 匹配已保存的子组 |
\\A | 匹配字符串的起始 |
七 中缀表达式( : : )
中缀表达式得关键字是::,下方代码通过match+::进行模式匹配。
只有当第一个case条件中的各级匹配成功之后,才会执行第一条语句,并执行println语句。
匹配不成功则输出对应的语句
object num1{
def main(args: Array[String]): Unit = {
List(1,2,3,4,5,6,7) match {
case one :: two :: three :: four :: rest => println(one,three,rest)
case _=>println("中缀表达式")
}
}
}
输出结果:
(1,3,List(5, 6, 7))
前四个数字分别与one,two,three,four匹配,剩下的[5,6,7]则分配给rest
object num2{
def main(args: Array[String]): Unit = {
List(1,2) match {
case one :: two :: three :: four :: rest => println(one,three,rest)
case _=>println("中缀表达式")
}
}
}
输出结果:
中缀表达式
数字1与数字2分别与one,two匹配,但是没有全部匹配,在println中也无法输出three,rest
所以匹配失败,输出中缀表达式
八 闭包(Closure)
在Scala中,你可以在任何领域定义函数、包、类,在函数体内可以访问到应用作用域的任何变量
闭包是一个函数,其返回值依赖于声明在函数包部的一个或者多个变量
通常来说,可以将闭包看作是可以访问一个函数里面局部变量的另一个函数
object Demo7_closesure {
def main(args: Array[String]): Unit = {
def mulby(factor:Double) = (x:Double) =>
factor * x
val triple = mulby(3)
val half = mulby(0.5)
println(triple(14) + "--->" + half(14))
}
}
mulby首次调用的时候我们将factor设置为3,该变量会在(x:Double) => factor * x函数中的被引用,也就是说对应的函数变为了:(x:Double) => 3 * x。该函数存储到了triple
mulby二次调用的时候我们将factor设置为0.5,该变量会在(x:Double) => factor * x函数中的被引用,也就是说对应的函数变为了:(x:Double) => 0.5 * x。该函数存储到了half
在这里,每个函数都称为闭包(closure)。
- 典型例题
object num{
def main(args: Array[String]): Unit = {
val result = someCurring(4)(3)
println(result)
}
def someCurring(x:Int):(Int) => Int = {
def s(y:Int) = 2*x
s
}
}
输出8
object num{
def main(args: Array[String]): Unit = {
val result = someCurring(4)(3)
println(result)
}
def someCurring(x:Int):(Int) => Int = {
def s(y:Int) = 2*y
s
}
}
输出6
九 柯里化(Curring)
指的将两个参数的函数变为一个新的一个参数的函数的过程。
柯里化和闭包性质相同
package com.qf.bigdata.scala.day3
object Demo8_Currying {
def main(args: Array[String]): Unit = {
def totalSum(num1:Int, num2:Int) = println(num1 + num2)
// totalSum(1,2)
// totalSum(1)(2)
def total(num1:Int) = (num2:Int) => println(num1 + num2)
totalSum(1, 2)
total(1)(2)
}
}
十 Scala特质和Java的Interface接口
1 特质与interface比较
Scala的特质具有Java的接口和类的部分特性:
1.Scala的特质能够提供具体的方法的实现,而Java接口只有方法的定义,这点很像Java的抽象类
2.Scala同Java,都不能进行多继承,但是前者可以实现多特质,使用with关键字。这点和Java的接口相同
3.Scala的特质在对象生成时临时加入,Java没有这个特性
4.Java只能在类层面添加接口的实现,而Scala可以在类和对象层面上混入特质
2 Java抽象类
1.抽象类不能被实例化,实例化的工作应该交由它的子类来完成,它只需要有一个引用即可
2.抽象方法必须由子类来重写
3.只要包含一个抽象方法的抽象类,该方法必须要定义成抽象类,不管是否还包含其他方法
4.抽象类中可以包含具体的方法,也可以不包含抽象的方法
5.子类中的抽象方法不能与父类中的抽象方法同名
6.abstract不能与final并列修饰同一类
7.abstract不能与private、static、final、native并列修饰同一个方法
3 接口
1.interface的方法的访问权限应该被声明为public
2.接口可以定义“成员变量”,因为接口中的成员变量可以自动变为public static final,可以通过类名点访问
3.接口中不存在实现的方法
4.实现接口的非抽象类必须要实现该接口的所有方法,抽象类可以不用实现
5.不能通过new实例化一个接口,但是可以声明一个接口变量,该变量必须引用一个实现该接口的类的对象
6.在实现多接口的时候一定要避免方法名的重复
4 特质
1.scala中的类只能继承一个超类,可以扩展任意数量的特质
2.特质可以要求实现他们类具备特定的字段、方法和超类
3.与Java 接口不同,Scala特质提供方法和字段的实现
4.当将多个特质叠加使用的时候,顺序很重要
5.若多重继承的基类具有相同的字段或者方法,就会引发菱形继承问题,造成问题的复杂性
6.使用特质可以达到多重继承的类似效果
7.首先调用超类的构造器。
8.特质构造器在超类构造器之后、类构造器之前执行。所有特质构造完毕,子类被构造。
9. 每个特质中,父特质先被构造。
十一 set集合
是一个没有先后次序的集合。如果要有序SortedSet,这种集合元素会以某种顺序访问
- 代码
object ScalaSetTest{
def main(args: Array[String]): Unit = {
// 创建一个可变set
val set: mutable.HashSet[Int] = new mutable.HashSet[Int]()
// 往set中加入元素1
set+=1
// 添加另一个set中元素
set.add(2)
//添加序列
set ++= Set(1,8,9)
// 移除一个元素
set-=2
// remove等价于-=
set.remove(2)
set.foreach(print)
}
}
//Set会自动去重
输出结果:
9
1
8
十二 Option
1 Option的介绍
为了让所有东西都是对象的目标更加一致,也为了遵循函数式编程的习惯,Scala鼓励你在变量和函数返回值的时候可能不会引用任何值的时候使用Option类型。在没有值的时候,使用None,它是Option的一个子类,在有值的时候,就使用some来包含这个值,它也算是Option的一个子类
2 Option作用
1.Option可以避免判断为空NUll
2.Option的一个非常惯用的做法是,把Option当成一个集合来看待,集合的大小是1或者0,所以可以把map,filter,foreach等操作在Option上
3.适用于模式匹配,例如下:nameMaybe中有值的时候,走第一个case。没有值的时候走None的逻辑
val nameMaybe = request getParameter "name"
nameMaybe match {
case Some(name) =>
println(name.trim.toUppercase)
case None =>
println("No name value")
}
十三 操作符
1 中置操作符
标准:a 标识符 b
举例:
1 to 10等同于1.to(10)
1 -> 10等同于1.->(10)
2 一元操作符
中置操作符是二元的,他有一个显示参数和一个隐式参数,只有一个操作符的参数称为一元操作符。如果它出现在参数之后,他就是后置操作符。
标准: a 标识符
举例:
1 toString 等同于 1.toString
<+、-、!、~>这四个操作符可以作为前置操作符,出现在参数之前,他们可以被转换成名为unary_操作符的方法调用
举例:
+ a 等同于 a.unary_-一样
3 赋值操作符
标准:操作符=以下表达式
例如:
a += b 等同于 a = a + b
注意:
1.<= >= != 不是赋值操作符
2.以=开头的操作符不是赋值操作符
3.如果a有一个名为操作符=的方法,那么该方法会被直接调用
十四 Type关键字
Scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型。
type相当于一个类型别名。
Type通常用于声明某种复杂类型,或者用于定义一个抽象类型
类型1:
object test extends App{
//将type(S)设置为String类型
type S = String
var name:S = "ZXY"
println(name)
}
类型2:
object ABC {
class A{
//定义一个type变量
type T
def text(t:T): Unit ={
println(t)
}
}
class B extends A{
//继承A类,并重载type,设置为Int类型
override type T = Int
}
class C extends A{
//继承A类,并重载type,设置为String类型
override type T = String
}
def main(args: Array[String]): Unit = {
//new一个类
val b: B = new B()
val c: C = new C()
b.text(21)
c.text("zxy")
}
}
以上是关于Scala学习补充篇的主要内容,如果未能解决你的问题,请参考以下文章
linux打开终端如何启动scala,如何在终端下运行Scala代码片段?