环境安装

Scala运行在 JVM 上,所以需要先安装配置 JDK 环境。

下载 Scala:

因为学习Scala是为了Spark使用,所以下载的 jdk、Scala 版本最好和Spark官网上要求的一致:

  1. Spark runs on Java 8/11/17, Scala 2.12/2.13, Python 3.7+ and R 3.5+. Java 8 prior to version 8u201 support is deprecated as of Spark 3.2.0. For the Scala API, Spark 3.3.0 uses Scala 2.12. You will need to use a compatible Scala version (2.12.x).

将下载好的Scala进行解压:

  1. tar -zxvf scala-2.12.16.tgz -C /opt/module

配置环境变量:

  1. export SCALA_HOME=/opt/module/scala-2.12.16
  2. export PATH=$PATH:$SCALA_HOME/bin

验证:

  1. scala -version

和 Java 一样,Scala也可以使用 Idea 进行编写。所以还需要安装 Idea 来编写代码。

HelloWorld

使用scalac编译运行

和 Java 的 javac 编译几乎一样。

编写HelloScala.scala

  1. object HelloScala {
  2. // Unit 表示返回值为空
  3. def main(args: Array[String]): Unit = {
  4. println("hello world") // scala不需要写分号
  5. }
  6. }

使用scalac 编译成class:

  1. scalac HelloScala.scala

编译后会生成两个文件:

  • HelloScala.class
  • HelloScala$.class

运行编译后的class:

  1. scala HelloScala

将class反编译为Java

HelloScala.class反编译结果为:

  1. import scala.reflect.ScalaSignature;
  2. @ScalaSignature(bytes = "\006\001%:Q\001B\003\t\002!1QAC\003\t\002-AQAE\001\005\002MAQ\001F\001\005\002U\t!\002S3mY>\0346-\0317b\025\0051\021a\002\037f[B$\030PP\002\001!\tI\021!D\001\006\005)AU\r\0347p'\016\fG.Y\n\003\0031\001\"!\004\t\016\0039Q\021aD\001\006g\016\fG.Y\005\003#9\021a!\0218z%\0264\027A\002\037j]&$h\bF\001\t\003\021i\027-\0338\025\005YI\002CA\007\030\023\tAbB\001\003V]&$\b\"\002\016\004\001\004Y\022\001B1sON\0042!\004\017\037\023\tibBA\003BeJ\f\027\020\005\002 M9\021\001\005\n\t\003C9i\021A\t\006\003G\035\ta\001\020:p_Rt\024BA\023\017\003\031\001&/\0323fM&\021q\005\013\002\007'R\024\030N\\4\013\005\025r\001")
  3. public final class HelloScala {
  4. public static void main(String[] paramArrayOfString) {
  5. HelloScala$.MODULE$.main(paramArrayOfString);
  6. }
  7. }

HelloScala$.class 反编译结果为:

  1. import scala.Predef$;
  2. public final class HelloScala$ {
  3. public static HelloScala$ MODULE$;
  4. public void main(String[] args) {
  5. Predef$.MODULE$.println("hello world");
  6. }
  7. private HelloScala$() {
  8. MODULE$ = this;
  9. }
  10. }

经过反编译成java后,可以大致了解其运行机制:

  1. 我们运行的 HelloScalamain()方法,其实实际调用的是 HelloScala$MODULE$ 对象的main()方法
  2. HelloScala$MODULE$对象实际上就是我们在Scala中创建的 object HelloScala,叫做伴生对象(把HelloScala叫做伴生对象的伴生类,把HelloScala$叫做伴生对象的所属类)
  3. HelloScala$main()方法不是static的,需要通过对象才能调用
  4. HelloScala$MODULE$对象就是本身,所以拥有打印hello worldmain()方法

经过上面的分析,我们可以发现,我们只需要用java去执行HelloScala类的静态main()方法也可以执行Scala编译的结果,但是需要引入scala.Predef$(在Scala的lib包中有):

  1. # 注意:Linux的jar包中间以冒号分隔,Windows的以分号分隔
  2. java -cp $SCALA_HOME/lib/scala-library.jar: HelloScala

使用Idea编写HelloWorld

在 Idea 中安装插件 Scala,然后便可以像编写Java项目一样正常编写Scala了。

开发步骤:

  1. 使用Idea创建Maven项目,选择 JDK 1.8。
  2. src/main下创建scala文件夹,然后Make Directory as设置成Sources Root

    maven项目中的java文件夹可以继续保留着,因为Scala支持Java的大部分类库,所以项目中的Scala、java源文件是可以混合着使用的

  1. 在项目上右键,选择 Add Framework Support... ,勾选Scala并配置Scala软件位置,为项目添加Scala框架支持
  2. 然后可以像Java一样创建一个包chapter01
  3. 然后在包内创建Scala Class
  4. 选择Scala Class后会提示创建Scala的类型:ClassCase ClassObjectCase ObjectTrait

此处因为我们需要直接运行HelloWorld,所以可以直接创建Object伴生对象

  1. package chapter01 // 包名
  2. // object关键字声明一个单例对象(伴生对象)
  3. object HelloWorld {
  4. // 定义 main 方法
  5. def main(args: Array[String]): Unit = {
  6. println("hello world")
  7. System.out.println("lalala") // 在Scala中可以直接使用Java的System类
  8. }
  9. }

伴生对象

为了达到纯粹的面向对象,消除掉Java类中的static静态属性,Scala使用了伴生对象。

伴生对象用法示例

示例:
Java中的代码Student.java

  1. public class Student {
  2. private String name;
  3. private Integer age;
  4. private static String school = "庞各庄小学"; // 此处有static类的静态属性
  5. public Student(String name, Integer age) {
  6. this.name = name;
  7. this.age = age;
  8. }
  9. public void printInfo() {
  10. // Student.school通过类直接调用了属性,不是纯粹的面向对象
  11. System.out.println(this.name + " " + this.age + " " + Student.school);
  12. }
  13. public static void main(String[] args) {
  14. Student zhangSan = new Student("张三", 18);
  15. Student liSi = new Student("李四", 20);
  16. zhangSan.printInfo();
  17. liSi.printInfo();
  18. }
  19. }

Scala中的转换:Student.scala

  1. package chapter01
  2. // 定义一个类
  3. // 类后面可以直接在括号内声明类中的属性,Scala会自动认为其为构造方法
  4. class Student(name: String, age: Int) {
  5. def printInfo(): Unit = {
  6. // Student类可以直接使用伴生对象Stduent的相关属性和方法,Student.school、
  7. // 表面看起来似乎在School中有一个静态属性school,但是实际上是伴生对象object Student的属性。达到完全的面向对象
  8. println(this.name + " " + this.age + " " + Student.school)
  9. }
  10. }
  11. // 类Student的伴生对象,和类名完全一致,而且必须放在同一个文件中
  12. object Student {
  13. var school: String = "庞各庄小学"
  14. def main(args: Array[String]): Unit = {
  15. val zhangSan = new Student("张三", 18)
  16. val liSi = new Student("李四", 20)
  17. zhangSan.printInfo()
  18. liSi.printInfo()
  19. }
  20. }

编译的class

Scala的Student.scala最终生成的class。

Student.class:即class Student声明的属性、构造方法、方法

  1. import chapter01.Student;
  2. import chapter01.Student$;
  3. import scala.Predef$;
  4. import scala.reflect.ScalaSignature;
  5. @ScalaSignature(bytes = "\006\001\0213A\001D\007\001!!Aq\003\001B\001B\003%\001\004\003\005$\001\t\005\t\025!\003%\021\0259\003\001\"\001)\021\025i\003\001\"\001/\017\025\021T\002#\0014\r\025aQ\002#\0015\021\0259c\001\"\0016\021\0351d\0011A\005\002]Bq\001\017\004A\002\023\005\021\b\003\004=\r\001\006K\001\007\005\006{\031!\tA\020\002\b'R,H-\0328u\025\005q\021!C2iCB$XM\035\0312\007\001\031\"\001A\t\021\005I)R\"A\n\013\003Q\tQa]2bY\006L!AF\n\003\r\005s\027PU3g\003\021q\027-\\3\021\005e\001cB\001\016\037!\tY2#D\001\035\025\tir\"\001\004=e>|GOP\005\003?M\ta\001\025:fI\0264\027BA\021#\005\031\031FO]5oO*\021qdE\001\004C\036,\007C\001\n&\023\t13CA\002J]R\fa\001P5oSRtDcA\025,YA\021!\006A\007\002\033!)qc\001a\0011!)1e\001a\001I\005I\001O]5oi&sgm\034\013\002_A\021!\003M\005\003cM\021A!\0268ji\00691\013^;eK:$\bC\001\026\007'\t1\021\003F\0014\003\031\0318\r[8pYV\t\001$\001\006tG\"|w\016\\0%KF$\"a\f\036\t\017mJ\021\021!a\0011\005\031\001\020J\031\002\017M\034\007n\\8mA\005!Q.Y5o)\tys\bC\003A\027\001\007\021)\001\003be\036\034\bc\001\nC1%\0211i\005\002\006\003J\024\030-\037")
  6. public class Student {
  7. private final String name;
  8. private final int age;
  9. public Student(String name, int age) {}
  10. public void printInfo() {
  11. Predef$.MODULE$.println((new StringBuilder(2)).append(this.name).append(" ").append(this.age).append(" ").append(Student$.MODULE$.school()).toString());
  12. }
  13. public static String school() {
  14. return Student$.MODULE$.school();
  15. }
  16. public static void school_$eq(String paramString) {
  17. Student$.MODULE$.school_$eq(paramString);
  18. }
  19. public static void main(String[] paramArrayOfString) {
  20. Student$.MODULE$.main(paramArrayOfString);
  21. }
  22. }

Student$.class:即 object Student声明的属性、方法

  1. import chapter01.Student;
  2. import chapter01.Student$;
  3. public final class Student$ {
  4. public static Student$ MODULE$;
  5. private String school;
  6. public String school() {
  7. return this.school;
  8. }
  9. public void school_$eq(String x$1) {
  10. this.school = x$1;
  11. }
  12. public void main(String[] args) {
  13. Student zhangSan = new Student(", 18);
  14. Student liSi = new Student(", 20);
  15. zhangSan.printInfo();
  16. liSi.printInfo();
  17. }
  18. private Student$() {
  19. MODULE$ = this;
  20. this.school = ";
  21. }
  22. }