Scala入门
1.概述
1.1 什么是Scala
Java不是纯面向对象的语法,比如Java中的基本数据类型和static关键字;基本数据类型不是引用类型,而static所描述的属性和方法也不是对象层面的;
-
Scala并不是一个单词,而是Scalable Language两个单词的缩写
-
Scala是一门可伸缩的软件编程语言;之所以叫做可伸缩语言,是因为这门语言既体现了面向对象的编程思想,也有函数式编程,融合了多种不同的语言范式,体现了不同语言的特性
-
Scala官网:https://www.scala-lang.org/
-
截至到2020年8月,Scala最新版本为2.13.3,支持JVM和JavaScript
1.2 为什么学习Scala
Scala学习的版本
- 2.12.11
- 大版本号:2.12 ,小版本号是.11 不需要记 小版本号
- 2.12和2.13差别不大
之所以学习scala是因为:
- 大数据主要的批处理计算引擎框架Spark是基于Scala语言开发的
- 大数据主要的流式计算引擎框架Flink也提供了Scala相应的API
- 大数据领域中函数式编程的开发效率更高,更直观,更容易理解
Spark: 95% Scala开发 5% Java开发
flink: 30 Scala开发 70% Java
Kafka : 100% Scala开发
函数式编程 面向功能
1.3 Java & Scala
Martin Odersky是狂热的编译器爱好者,长时间的编程后,希望开发一种语言,能够让写程序的过程变得简单,高效,所以当接触到Java语言后,感受到了这门语言的魅力,决定将函数式编程语言的特性融合到Java语言中,由此产生了2门语言(Pizza & Scala),这两种语言极大地推动了Java语言的发展
- JDK1.5的泛型,增强for循环,自动类型转换等都是从Pizza语言引入的新特性
- JDK1.8的类型推断,λ(lambda)表达式是从Scala语言引入的新特性
由上可知,Scala语言是基于Java开发的,所以其编译后的文件也是字节码文件,并可以运行在JVM中。
2.快速上手
2.1 Scala环境安装
1)安装JDK1.8
2)安装Scala2.12
- 解压文件:scala-2.12.11.zip,解压目录要求无中文无空格
- 配置环境变量
3)环境测试
如果出现如下窗口内容,表示环境安装成功
2.2 IDEA中Scala插件安装
默认情况下IDEA不支持Scala的开发,需要安装Scala插件
注意
idea中搜索的插件的版本和idea自身版本有关系;并且要下载idea版本对应的scala版本
可以参考这个说明:
https://www.bilibili.com/video/BV1Xh411S7bP?p=8
访问网址可以自己找自己idea版本对应的scala进行下载:
https://plugins.jetbrains.com/plugin/1347-scala/versions
2.3 Hello Scala案例
1.创建Maven项目
对maven gav概念不熟可参考:
https://blog.csdn.net/weixin_43589563/article/details/119943634
2.给项目增加Scala框架支持
默认情况,IDEA中创建项目时不支持Scala的开发,需要添加Scala框架的支持
选择create的时候,由于配置了scala的环境变量,idea会自动找到本地安装好的scala类库!
从上图就能看到就是自己安装的scala目录
3.创建类
在main文件目录中创建Scala类:com.atguigu.bigdata.scala.HelloScala
注意选择Object
package com.atguigu.bigdata.scala
object HelloScala {
def main(args: Array[String]): Unit = {
System.out.println("Hello Scala")
println("Hello Scala")
}
}
2.4 案例分析
package com.yato.bigdata.scala.chapter01
/**
* Object : 声明类的关键字; 在声明类的同时可以声明对象 类名也是对象名
* class 也是声明类的关键字,但是不会同时声明对象
* def: 用于声明函数(方法)的关键字;
* main: 方法名称
*
*
* (args: Array[String]) :
* 方法名后面的小括号里是参数声明,多个参数之间用逗号隔开;
*
* args: Array[String] :
* 参数后面紧跟着的是参数类型,参数和参数类型用冒号隔开,参数名称在前
* 体现了和java不同的风格:
* java是强类型语言,在运行之前,所有数据都要明确类型
* scala也是 强类型语言,scala更关心如何使用参数,java更关心类型
*
* Array[String]:
* Scala是完全面向对象的语言,数组在scala中是Array类
* Java中的数组并不是一个类,String[] s 只是表示a变量存储String类型数组地址
*
* 和 参数:参数类型 这种风格一致,Scala中定义方法的时候
* 方法返回值类型在方法名后面 => test() : void
*
* Unit: Scala是完全面向对象的语言,java中用关键字void表示没有返回值 Scala用Unit类型表示没有返回值
*
* \=: 表示赋值,体现了Scala万物皆对象 将方法体对象 赋值给 函数
*
* {} : 方法体
*
* Scala是基于java开发的,java的代码可以直接在scala中使用
*
* scala会省略分号
* 一般你每一行完成一段逻辑的代码编写
* 如果一行写多个逻辑,那么需要用分号隔开
*
*
*/
object Scala01_HelloScala {
def main(args: Array[String]): Unit = {
System.out.println("Hello Scala")
}
}
类名和Scala文件的关系
(1)对于java来说,如果java源文件中有public 类,那么文件名必须和此类名保持一致
jvm执行java代码的规则就是 找到main方法,开始执行
(2)对于Scala来说,通过Object或者class声明类,和Scala文件名没有严格的关系
Scala执行流程
.scala源文件
经过scalac工具
编译成.class文件
反编译工具
由于Scala是基于Java的,所以学习的时候可以用反编译的方式将Scala源码所编译成的.class字节码文件反编译为java代码,来进行对比学习;
(1) 查看.class 文件
1.javap -c -l 类名
这里类名为.class文件的名字 不带.class
比如:
(2)jd-gui.exe
这是java反编译工具;可以直接打开.class文件,将其反编译为java代码
反编译对比
scala最后也要编译成.class文件,但是不会在idea的target目录下,从idea的target目录下查看scala编译后的代码会发现还是源代码;
因此只能右击编译代码然后open in explorer在本地目录下找到.class文件,然后用反编译工具jd-gui.exe
打开
scala源码:
object Scala01_HelloScala {
def main(args: Array[String]): Unit = {
System.out.println("Hello Scala")
}
}
反编译成了两个.class文件:
(1)不带$的.class文件反编译代码
package com.yato.bigdata.scala.chapter01;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes="...太长忽略...")
public final class Scala01_HelloScala
{
public static void main(String[] paramArrayOfString)
{
Scala01_HelloScala$.MODULE$.main(paramArrayOfString);
}
}
- 这个类直接对应着scala类反编译成的java类
- scala中的main方法会被反编译成java中的main方法
- final类 不可继承类 最终的类
- main方法中:
通过Scala01_HelloScala$
类,调用其MODULE$
属性的main(paramArrayOfString)
方法
查看Scala01_HelloScala$类
(2)带$的.class文件
package com.yato.bigdata.scala.chapter01;
import java.io.PrintStream;
public final class Scala01_HelloScala$
{
public static MODULE$;
static
{
new ();
}
public void main(String[] args)
{
System.out.println("Hello Scala");
}
private Scala01_HelloScala$() { MODULE$ = this; }
}
-
静态代码块中调用构造方法new当前类的对象
-
构造器中将对象赋值给MODULE$属性;所以MODULE$就是一个对象
-
构造器还是private,所以是单例的
小结
Object Scala01_HelloScala
会编译成两个.class文件,一个带$
,一个不带$
Scala01_HelloScala.class
是scala源码反编译成的,而Scala01_HelloScala$.class
则是伴生类- 由于scala是完全面向对象的语言,所以没有静态语法
- 由于没有静态语法,那么
Scala01_HelloScala.scala
怎么反编译成的.class中必须要有publics static void main
主方法,怎么执行呢? - 只能通过模拟生成静态方法
- 怎么模拟?
编译时将当前类生成一个特殊的类Scala01_HelloScala$
,然后创建此类的对象来调用这个对象的main方法 - 伴随着
Scala01_HelloScala
类产生的Scala01_HelloScala$
类所创建的对象 叫做 伴生对象; - 伴生对象的内容,都可以通过类名访问,从而来模拟java中的静态语法
- 伴生对象的语法规则:使用object声明的类 会生成伴生对象
- 所以用object声明的类中,可以直接用类名访问内容
二、方法的映射
object Scala01_HelloScala {
def main(args: Array[String]): Unit = {
System.out.println("Hello Scala")
}
}
scala中的main如何变成psvm?
public final class Scala01_HelloScala
{
public static void main(String[] paramArrayOfString)
{
Scala01_HelloScala$.MODULE$.main(paramArrayOfString);
}
}
- static:有了伴生对象 模拟静态语法,就不用考虑了
- public : scala中没有public关键字 不带权限修饰符默认就是public
- void : 对应scala Unit类型
所以scala中,一个类要写main方法,必须写成Object,否则没有伴生对象,无法模拟public static void main
(感觉没完全理解)
2.5自定义方法
package com.yato.bigdata.scala.chapter01
object Scala02_Method {
def main(args: Array[String]): Unit = {
//todo 2.调用方法
test()
//todo 3.Object声明类和对象,那么也能通过对象来调用
Scala02_Method.test()
//todo 4.额外说明:
// 如果将Scala02_Method看作类的话,那么可以将Scala02_Method.test() 看作是通过类来调用
// 因此很像Java中的static方法
// 但是Scala是完全面向对象的,没有static关键字
// 可以用Object关键字声明对象方法访问方法,来模仿静态语法
}
//todo 1.声明一个方法
def test() : Unit = {
println("test...")
}
}