Scala扩展部分
类型参数
Scala的类型参数与Java的泛型是一样的,可以在集合、类、函数中定义类型参数,从而保证程序更好的健壮性。
泛型类
泛型类,顾名思义,其实就是在类的声明中定义一些泛型类型,然后在类内部的字段或者方法,就可以使用这些泛型类型。
使用泛型类,通常是需要对类中的某些成员,比如某些字段和方法中的参数或变量进行统一的类型限制,这样可以保证程序更好的健壮性和稳定性。
如果不使用泛型进行统一的类型限制,那么在后期程序运行过程中难免会出现问题,比如传入了不希望的类型导致程序出问题。
在使用泛型类的时候,比如创建泛型类的对象,只需将类型参数替换为实际的类型即可。
Scala自动推断泛型类型特性:直接给使用泛型类型的字段赋值时,Scala会自动进行类型推断。
泛型类的定义如下:
1 | //定义一个泛型类 |
使用上述的泛型类,只需要使用具体的类型代替类型参数即可。
1 | object GenericityDemo { |
泛型函数
泛型函数,与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的变量,或者多个变量,进行强制性的类型限制。
与泛型类一样,你可以通过给使用了泛型类型的变量传递值来让Scala自动推断泛型的实际类型,也可以在调用函数时,手动指定泛型类型。
案例:卡片售卖机,可以指定卡片的内容,内容可以是String类型或Int类型
1 | object GenericityFunction { |
协变和逆变
Scala的协变和逆变是非常有特色的,完全解决了Java中的泛型的一大缺憾!
举例来说,Java中,如果有Professional是Master的子类,那么Card[Professionnal]是不是Card[Master]的子类?答案是:不是。因此对于开发程序造成了很多的麻烦。
而Scala中,只要灵活使用协变和逆变,就可以解决Java泛型的问题。
协变定义形式如:trait List[+T] {}
当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,即List[S]可以泛化为List[A],也就是被参数化,类型的泛化方向与参数类型的方向是一致的,所以称为协变(covariance)。
逆变定义形式如:trait List[-T] {}
当类型S是类型A的子类型,则Queue[A]反过来可以认为是Queue[S}的子类型,也就是被参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变(contravariance)。
小结:如果A是B的子类,那么在协变中,List[A]就是List[B]的子类; 在逆变中,List[A]就是List[B] 的父类。
协变案例:只有大师以及大师级别以下的名片都可以进入会场
1 | package lagou.cn.part11 |
Akka
Akka是Java虚拟机平台上构建高并发、分布式和容错应用的工具包和运行时。
Akka用Scala语言编写,同时提供了Scala和Java的开发接口。
Akka处理并发的方法基于Actor模型,Actor之间通信的唯一机制就是消息传递。
-
Actor
Scala的Actor类似于Java中的多线程编程。
但是不同的是,Scala的Actor提供的模型与多线程有所不同。Scala的Actor尽可能地避免锁和共享状态,从而避免多线程并发时出现资源争用的情况,进而提升多线程编程的性能。
Actor可以看作是一个个独立的实体,Actor之间可以通过交换消息的方式进行通信,每个Actor都有自己的收件箱(Mailbox)。
一个Actor收到其他Actor的信息后,根据需要作出各种相应。消息的类型可以是任意的,消息的内容也可以是任意的。
-
ActorSystem
在Akka中,ActorSystem是一个重量级的结构。
它需要分配多个线程,所以在实际应用中,ActorSystem通常是一个单例对象,我们可以使用这个ActorSystem创建很多Actor。
-
Akka案例
创建一个maven项目,支持Scala开发
在项目的pom文件中增加如下依赖:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37<properties>
<encoding>UTF-8</encoding>
<scala.version>2.12.3</scala.version>
<scala.compat.version>2.11</scala.compat.version>
<akka.version>2.4.17</akka.version>
</properties>
<dependencies>
<!-- 添加akka的actor依赖 -->
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-actors</artifactId>
<version>2.11.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-actor -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.11</artifactId>
<version>2.3.16</version>
</dependency>
<!-- 添加akka的actor依赖 -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_${scala.compat.version}</artifactId>
<version>${akka.version}</version>
</dependency>
<!-- 多进程之间的Actor通信 -->
<!-- https://mvnrepository.com/artifact/com.typesafe.akka/akka-remote -->
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_${scala.compat.version}</artifactId>
<version>${akka.version}</version>
</dependency>
</dependencies>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import scala.io.StdIn
class HelloActor extends Actor {
//接收消息并进行处理
override def receive: Receive = {
case "吃了吗" => println("吃过了")
case "吃的啥" => println("北京烤鸭")
case "拜拜" => {
//关闭自己
context.stop(self)
//关闭ActorSystem
context.system.terminate()
}
}
}
object HelloActor {
//通过ActorSystem创建线程池对象myFactory
private val myFactory = ActorSystem("myFactory")
//通过myFactory.actorOf来创建一个Actor
private val helloActorRef: ActorRef = myFactory.actorOf(Props[HelloActor], "helloActor")
def main(args: Array[String]): Unit = {
var flag = true
while (flag) {
print("请输入发送的消息:")
val consoleLine: String = StdIn.readLine()
//!发送消息
helloActorRef ! consoleLine
if (consoleLine.equals("拜拜")) {
flag = false
println("程序即将结束!")
}
//让程序休眠100毫秒
Thread.sleep(100)
}
}
}