一文速通Scala

  • Post author:
  • Post category:其他





scala相关概述;

scala环境搭建

scala小案例



Scala和Java对比【理解】

  1. Java程序编译执行流程

    在这里插入图片描述

    编写java源代码,通过javac将源代码编译为后缀名为.class的字节码文件,然后被类加载器加载到JVM(java虚拟机)中,由它将后缀名为.class的字节码文件转化为操作系统能够直接识别的指令,然后把这些指令交给操作系统来执行。

  2. Scala程序编译执行流程

    在这里插入图片描述

    scala源代码,通过scalac编译器将其编译为字节码文件。不同点(两个点),scala通过scalac来编译,scala程序的执行,除了要依赖java类库,还要依赖scala类库。后面的内容都一样,把这些内容加载到类加载器JVM虚拟机中。由它转化为操作系统直接识别的指令,并交给操作系统来执行。

java程序和scala程序的执行流程对比。

代码对比:

定义个学生类,属性为姓名和年龄。

//定义学生类
public class Student{
    private String name;		//姓名
    private int age;			//年龄
    
    //空参和全参构造
    public Student(){}
    
    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }
    
    //getXxx()和setXxx()方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

//测试类
public class StudentDemo {
     public static void main(String[] args) {
        Student s1 = new Student("张三", 23);	//创建Student类型的对象s1, 并赋值
        System.out.println(s1);				 //打印对象, 查看结果.
    }
}

scala代码:

case class Student(var name:String, var age:Int)		//定义一个Student类
// 这里可以省去new的动作
val s1 = Student("张三", 23)							  //创建Student类型的对象s1, 并赋值
println(s1)											   //打印对象, 查看结果.



scala环境搭建【掌握】

scala程序运行需要依赖于Java类库,那么必须要有

Java运行环境

,scala才能正确执行. 所以要编译运行scala程序,需要:

  • JDK(JDK包含JVM)
  • Scala编译器(Scala SDK)
  1. 依次安装JDK
  2. 安装scala sdk
  3. 在idea中安装scala插件

安装JDK 1.8 64位版本,并配置好环境变量, 此过程略.

Scala SDK是scala语言的编译器,要开发scala程序,必须要先安装Scala SDK。本次安装的版本是: 2.11.12


步骤

  1. 下载Scala SDK.


    官方下载地址: scala-lang.org/download/


    输入这个地址,

    在这里插入图片描述

在这里插入图片描述

首先要确保电脑上已经安装了jdk1.8。

scala两种类型:一种是ide,一种是sbt控制台版本。这里我们选择的是sbt。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

msi是安装版,zip是压缩版。使用安装版。

在这里插入图片描述

更改安装路径。

不要直接安装到盘副目录下。

  1. 安装Scala SDK.


2.1 双击scala-2.11.12.msi,将scala安装在指定目录, 傻瓜式安装, 下一步下一步即可.



2.2 安装路径要合法, 不要出现中文, 空格等特殊符号.

  1. 测试是否安装成功


打开控制台,输入: scala -version

安装idea scala插件。IDEA默认是不支持scala程序开发的,所以需要在IDEA中安装scala插件, 让它来支持scala语言。

坑点:下载的idea插件,必须和安装scala的版本一致。



下载指定版本IDEA scala插件



1. 下载的Scala插件必须和你安装的IDEA版本一致



2. 官方下载地址: http://plugins.jetbrains.com/plugin/1347-scala

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

下载的scala插件一定要和idea版本一致。



IDEA配置scala插件

  1. 选择配置 > 选择插件

    在这里插入图片描述

  2. 点击小齿轮 > 选择从本地安装插件

在这里插入图片描述

  1. 找到下载的插件位置,直接加载zip,点击OK

  2. 重新启动IDEA



scala解释器【掌握】

概述,启动,执行,退出

scala解释器,编译和执行scala的代码,实时的进行交互,比较方便测试。

启动scala解释器,Win+R输入scala。

在这里插入图片描述

java的输出是:

System.out.println()

scala的输出为:

println("hello world")

输入一个:quit来退出。



scala小案例【掌握】

​提示用户录入他/她最想对自己说的一句话, 然后将这句话打印到控制台上.

scala可以兼容Java,来访问java库。

步骤:

  1. 因为涉及到键盘录入了, 所以先导包.
  2. 提示用户录入他/她最想对自己说的一句话.
  3. 接收用户录入的内容, 并打印.
//1. 导入Java中的Scanner类.							引入Java类库
import java.util.Scanner
//2. 提示用户录入他/她最想对自己说的一句话.			   Scala代码
println("请录入一句您最想对自己说的一句话: ")
//3. 打印用户录入的内容.								 Scala代码 + Java类库
//不忘初心, 方得始终, 做最好的自己!
// 因为接受的是字符串,所以用nextLine的方法来进行调用
println("我最想对自己说: " + new Scanner(System.in).nextLine())




  1. 掌握变量, 字符串的定义和使用
  2. 掌握数据类型的划分和数据类型转换的内容
  3. 掌握键盘录入功能
  4. 理解Scala中的常量, 标识符相关内容



常量【掌握】

常量指的是:

在程序的运行过程中, 其值不能发生改变的量



常量分为两类:

  • 字面值常量(常用的有以下几种) – 数值本身就是一个常量(和java相同)

    • 整型常量
    • 浮点型常量
    • 字符常量
    • 字符串常量
    • 布尔常量
    • 空常量
  • 自定义常量 – 通过特定关键字来人为制造的量
//整型常量
println(10)
//浮点型常量
println(10.3)
//字符常量, 值要用单引号括起来
println('a')
//字符串常量, 值要用双引号括起来
println("abc")
//布尔常量, 值只有true和false
println(true)
//空常量
println(null)



输出语句和分号【掌握】

输出语句分为:换行输出和不换行输出。换行输出通过println来实现,不换行输出通过print来实现。

scala的print或println都是可以来输出多个值,输出语句的小括号直接写多个值,通过英文半角的逗号隔开。

注意:

不管是println(), 还是print()语句, 都可以同时打印多个值.格式为: println(值1, 值2, 值3...)

Scala语句中, 单行代码最后的分号可写可不写. 如果是多行代码写在一行, 则中间的分号不能省略, 最后一条代码的分号可省略不写.

println("Hello, Scala!")			//最后的分号可写可不写
//如果多行代码写在一行, 则前边语句的分号必须写, 最后一条语句的分号可以省略不写.
println("Hello"); println("Scala")

不管是哪种输出,都可以打印出多个值,scala中的分号。单行代码分号可写可不写。



打招呼【掌握】

提示用户录入他/她的姓名和年龄, 接收并打印.

//1. 提示用户录入姓名.
println("请录入您的姓名: ")
//2. 接收用户录入的姓名.
val name = StdIn.readLine()
//3. 提示用户录入年龄.
println("请录入您的年龄: ")
//4. 接收用户录入的年龄.
val age = StdIn.readInt()
//5. 将用户录入的数据(姓名和年龄)打印到控制台上.
println(s"大家好, 我叫${name}, 我今年${age}岁了, 很高兴和大家一起学习Scala!")

导包,提示用户录入信息,并接受,最后把信息输出到控制台



变量【掌握】

变量, 指的就是在程序的执行过程中,

其值可以发生改变的量

。定义格式如下:



语法格式

Java变量定义

int a = 0;

在scala中,可以使用

val

或者

var

来定义变量,语法格式如下:

val/var 变量名:变量类型 = 初始值

其中


  • val

    定义的是

    不可重新赋值的变量

    ,也就是

    自定义常量

    .

  • var

    定义的是

    可重新赋值

    的变量


注意: scala中定义变量时, 类型写在变量名后面


java定义变量时,数据类型写在前面。scala数据类型写在变量名后面,中间用冒号连接。

**需求:**定义一个变量保存一个人的名字”tom”


步骤

  1. 打开scala解释器
  2. 定义一个字符串类型的变量用来保存名字
scala> val name:String = "tom"
name: String = tom

给名字变量进行重新赋值为Jim,会报出error,因为值只能赋值一次,不可以重新赋值。

scala> name = "Jim"
<console>:12: error: reassignment to val
       name = "Jim"

使用

var

重新定义变量来保存名字”tom”,并尝试重新赋值为Jim,观察其运行结果。

scala> var name:String = "tom"
name: String = tom

scala> name = "Jim"
name: String = Jim

val和var都可以用来修饰变量,应该来用谁比较好?

注意: 优先使用

val

定义变量,如果变量需要被重新赋值,才使用

var

使用类型推断来定义变量

scala的语法要比Java简洁,我们可以使用一种更

简洁

的方式来定义变量。变量名的类型不写,由scala直接进行类型推断。


示例

使用更简洁的语法定义一个变量保存一个人的名字”tom”


参考代码

scala> val name = "tom"
name: String = tom

scala可以自动根据变量的值来自动推断变量的类型,这样编写代码更加简洁。自动根据变量的值来推断字段类型,让编写更加的简洁。



字符串【掌握】

scala字符串的方式有三种:

  • 使用双引号
  • 使用插值表达式
  • 使用三引号


双引号

,和java相似,包裹的是字符串值:

val/var 变量名 = “hadoop”

有一个人的名字叫”hadoop”,请打印他的名字以及名字的长度。

scala> println(name + name.length)
hadoop6


插值表达式

:scala中,使用插值表达式来定义字符串,避免大量字符串的拼接。

val/var 变量名 = s"${变量/表达式}字符串"

注意:

  • 在定义字符串之前添加

    s
  • 在字符串中,可以使用

    ${}

    来引用变量或者编写表达式

定义若干个变量,分别保存:“zhangsan”、23、“male”,定义一个字符串,保存这些信息。

打印输出:name=zhangsan, age=23, sex=male

scala> val name = "zhangsan"
name: String = zhangsan

scala> val age = 23
age: Int = 23

scala> val sex = "male"
sex: String = male

scala> val result = s"name=${name}, age=${age}, sex=${sex}"
result: String = name=zhangsan, age=23, sex=male

scala> println(result)
name=zhangsan, age=23, sex=male

这个和python中的f-string的操作很是相似。


使用三引号

如果有大段的文本需要保存,就可以使用

三引号

来定义字符串。例如:保存一大段的SQL语句,三个引号中间的所有内容都将作为字符串的值。

语法:

val/var 变量名 = """字符串1
字符串2"""

定义一个字符串,保存以下SQL语句,

select
	*
from
    t_user
where
    name = "zhangsan"

打印该SQL语句:

val sql = """select
     | *
     | from
     |     t_user
     | where
     |     name = "zhangsan""""

println(sql)



惰性赋值【掌握】

很长的SQL语句如果直接加载到JVM中,会有很大的内存开销, 如何解决这个问题呢?

当有一些变量保存的数据较大时,而这些数据又不需要马上加载到JVM内存中。就可以使用

惰性赋值

来提高效率。


语法格式:

lazy val/var 变量名 = 表达式


示例

在程序中需要执行一条以下复杂的SQL语句,我们希望只有用到这个SQL语句才加载它。

加载到JVM内存中了,此时又不需要立马用到SQL内容,就会占用内存资源。在定义变量的前面加上lazy,再和刚才的写法一样,就是普通的定义变量的写法。

"""insert overwrite table adm.itcast_adm_personas
    select
    a.user_id,
    a.user_name,
    a.user_sex,
    a.user_birthday,
    a.user_age,
    a.constellation,
    a.province,
    a.city,
    a.city_level,
    a.hex_mail,
    a.op_mail,
    a.hex_phone,
    a.fore_phone,
    a.figure_model,
    a.stature_model,
    b.first_order_time,
    b.last_order_time,
      ...
    d.month1_hour025_cnt,
    d.month1_hour627_cnt,
    d.month1_hour829_cnt,
    d.month1_hour10212_cnt,
    d.month1_hour13214_cnt,
    d.month1_hour15217_cnt,
    d.month1_hour18219_cnt,
    d.month1_hour20221_cnt,
    d.month1_hour22223_cnt
    from gdm.itcast_gdm_user_basic a
      left join gdm.itcast_gdm_user_consume_order b on a.user_id=b.user_id
    left join gdm.itcast_gdm_user_buy_category c on a.user_id=c.user_id
    left join gdm.itcast_gdm_user_visit d on a.user_id=d.user_id;"""

只有当使用到这个内容的时候,才会去加载它。

scala> lazy val sql = """insert overwrite table adm.itcast_adm_personas
     |     select
     |     a.user_id,
	....
     |     left join gdm.itcast_gdm_user_buy_category c on a.user_id=c.user_id
     |     left join gdm.itcast_gdm_user_visit d on a.user_id=d.user_id;"""
sql: String = <lazy>



标识符【掌握】

概述,


标识符就是用来给变量, 方法, 类等起名字的.

Scala中的标识符和Java中的标识符非常相似.

规范:

  • 变量或方法: 从第二个单词开始, 每个单词的首字母都大写, 其他字母全部小写(小驼峰命名法).

    zhangSanAge, student_Country, getSum
    
  • 类或特质(Trait): 每个单词的首字母都大写, 其他所有字母全部小写(大驼峰命名法)

    Person, StudentDemo, OrderItems
    
  • 包: 全部小写, 一般是公司的域名反写, 多级包之间用.隔开.

    com.itheima.add,  cn.itcast.update
    



数据类型【掌握】

强类型语言和弱类型语言的区别在于,语言对数据类型的划分是否精细。精细–>强类型语言,java,scala。

数据类型是用来约束变量(常量)的取值范围的. Scala也是一门强类型语言, 它里边的数据类型绝大多数和Java一样.我们主要来学习

  • 与Java不一样的一些用法
  • scala中数据类型的继承体系


数据类型

基础类型 类型说明
Byte 8位带符号整数
Short 16位带符号整数

Int
32位带符号整数
Long 64位带符号整数
Char 16位无符号Unicode字符
String Char类型的序列(字符串)
Float 32位单精度浮点数
Double 64位双精度浮点数
Boolean true或false


注意下 scala类型与Java的区别

[!NOTE]

  1. scala中所有的类型都使用

    大写字母

    开头
  2. 整形使用

    Int

    而不是Integer
  3. scala中定义变量可以不写类型,让scala编译器自动推断
  4. Scala中默认的整型是Int, 默认的浮点型是: Double


Scala类型层次结构


在这里插入图片描述

Unit类似java的关键字void。一般用于方法中,当方法没有返回值时,用unit作为scala返回值的类型。

Null类型是所有引用类型的子类。它的值只有一个:null

nothing是所有数据类型的子类。不需要创建Nothing类型的对象,一般它是结合异常来进行使用。

类型 说明
Any
所有类型

的父类,它有两个子类AnyRef与AnyVal ,相当于java的object
AnyVal
所有数值类型

的父类
AnyRef **所有对象类型(引用类型)**的父类
Unit 表示空,Unit是AnyVal的子类,它只有一个的实例{% em %}() {% endem %} 它类似于Java中的void,但scala要比Java更加面向对象
Null Null是AnyRef的子类,也就是说它是所有引用类型的子类。它的实例是{% em %}

null

{% endem %} 可以将null赋值给任何对象类型
Nothing 所有类型的

子类

, 不能直接创建该类型实例,某个方法抛出异常时,返回的就是Nothing类型,因为Nothing是所有类的子类,那么它可以赋值为任何类型

以下代码是否有问题?这样作会报错,null是所有引用类型的子类,int是数值型类型,所以这样作会出错。

val b:Int = null


Scala会解释报错:

Null类型并不能转换为Int类型,说明

Null类型并不是Int类型的子类



类型转换【掌握】

当Scala程序在进行运算或者赋值动作时, 范围小的数据类型值会自动转换为范围大的数据类型值, 然后再进行计算.例如: 1 + 1.1的运算结果就是一个Double类型的2.1. 而有些时候, 我们会涉及到一些类似于”四舍五入”的动作, 要把一个小数转换成整数再来计算. 这些内容就是Scala中的类型转换.

Scala中的类型转换分为

值类型的类型转换



引用类型的类型转换

, 这里我们先重点介绍:

值类型的类型转换

.

值类型的类型转换分为:

  • 自动类型转换
  • 强制类型转换


自动类型转换

  1. 解释


    范围小的数据类型值会自动转换为范围大的数据类型

    值, 这个动作就叫:自动类型转换.


    自动类型转换从小到大分别为:Byte, Short, Char -> Int -> Long -> Float -> Double

  2. 示例代码

    val a:Int = 3
    val b:Double = 3 + 2.21	//因为是int类型和double类型的值进行计算, 所以最终结果为: Double类型
    val c:Byte = a + 1	//这样写会报错, 因为最终计算结果是Int类型的数据, 将其赋值Byte类型肯定不行.
    


强制类型转换

  1. 解释

    范围大的数据类型值通过一定的格式(强制转换函数)可以将其转换成范围小的数据类型值, 这个动作就叫: 强制类型转换.


    注意: 使用强制类型转换的时候可能会造成精度缺失问题!

  2. 格式

val/var 变量名:数据类型 = 具体的值.toXxx		//Xxx表示你要转换到的数据类型
  1. 参考代码
val a:Double = 5.21
val b:Int = a.toInt
// 小数部分造成丢失,造成精度缺失问题

在这里插入图片描述

小的放进大的,叫自动类型转换。大的放小的,叫强制类型转换。



值类型和String类型之间的相互转换【掌握】

有两种方法,在值类型数据后,拼接一个空串来实现;值类型数据.toString方法来实现。


1. 值类型的数据转换成String类型


格式一

:

val/var 变量名:String = 值类型数据 + ""


格式二

:

val/var 变量名:String = 值类型数据.toString


将Int, Double, Boolean类型的数据转换成其对应的字符串形式。


参考代码

:

val a1:Int = 10
val b1:Double = 2.1
val c1:Boolean = true

//方式一: 通过和空字符串拼接的形式实现
val a2:String = a1 + ""
val b2:String = b1 + ""
val c2:String = c1 + ""

//方式二: 通过toString函数实现
val a3:String = a1.toString
val b3:String = b1.toString
val c3:String = c1.toString


2. String类型的数据转换成其对应的值类型


格式:

val/var 变量名:值类型 = 字符串值.toXxx	//Xxx表示你要转换到的数据类型

注意:

  • String类型的数据转成Char类型的数据, 方式有点特殊, 并不是调用toChar, 而是toCharArray
  • 这点目前先了解即可, 后续我们详细解释


需求:

​ 将字符串类型的整数, 浮点数, 布尔数据转成其对应的值类型数据.


参考代码:

val s1:String = "100"
val s2:String = "2.3"
val s3:String = "false"

//将字符串类型的数据转成其对应的: Int类型
val a:Int = s1.toInt
//将字符串类型的数据转成其对应的: Double类型
val b:Double = s2.toDouble
//将字符串类型的数据转成其对应的: Boolean类型
val c:Boolean = s3.toBoolean



键盘录入


概述


前边我们涉及到的数据, 都是我们写”死”的, 固定的数据, 这样做用户体验并不是特别好. 那如果这些数据是由用户录入, 然后我们通过代码接收, 就非常好玩儿了. 这就是接下来我们要学习的Scala中的”键盘录入”功能.


使用步骤

  1. 导包

格式: import scala.io.StdIn

  1. 通过

    StdIn.readXxx()

    来接收用户键盘录入的数据

接收字符串数据: StdIn.readLine()

接收整数数据: StdIn.readInt()

  • 提示用户录入字符串, 并接收打印.
println("请录入一个字符串: ")
val str = StdIn.readLine()
println("您录入的字符串内容为: " + str)
  • 提示用户录入整数, 并接收打印.
println("请录入一个整数: ")
val num = StdIn.readInt()
println("您录入的数字为: " + num)




  1. 理解运算符的相关概述
  2. 掌握算术, 赋值, 关系, 逻辑运算符的用法
  3. 掌握交换变量案例
  4. 理解位运算符的用法



算术运算符

理解。

注意: Scala中是没有三元运算符的, 被if-else给替代了.

注意:

  1. Scala中是没有++, –这两个算术运算符的, 这点和Java中不同.

  2. 整数相除的结果, 还是整数. 如果想获取到小数, 则必须有浮点型数据参与.


    例如: 10 / 3 结果是3 10 / 3.0 结果是: 3.3333(无限循环)

  3. 关于+号拼接字符串: 任意类型的数据和字符串拼接, 结果都将是一个新的字符串.

  4. 关于%操作, 假设求

    a % b

    的值, 它的底层原理其实是:

    a - a/b * b



赋值运算符

常量,变量

分为两类:基本赋值运算符,=;把常量值3赋值给int类型的变量a。

注意:

  1. 赋值运算符的左边必须是: 变量, 不能是常量. 例如: 3 = 5, 这种写法就是错误的.

  2. 关于扩展赋值运算符, 其实就是把左边的数据和右边的数据进行指定的操作, 然后把结果赋值给左边.


    例如; a += 3 就是把变量a的值和常量3进行加法操作, 然后把结果赋值给变量a



关系运算符

注意:

  1. 关系表达式不管简单还是复杂, 最终结果一定是Boolean类型的值, 要么是true, 要么是false.
  2. 千万不要把==写成=, 否则结果可能不是你想要的.

学过Java的同学会发现,,Scala的关系运算符和Java存在不同的地方。

答案是: 有。

需求描述 Scala代码 Java代码
比较数据值 == 或者 != equals()方法
比较引用值(地址值) eq方法 == 或者 !=


示例

有一个字符串”abc”,再创建第二个字符串,值为:在第一个字符串后拼接一个空字符串。

然后使用比较这两个字符串是否相等、再查看它们的引用值是否相等。


参考代码

val s1 = "abc"
val s2 = s1 + ""
s1 == s2     //结果是: true,  因为比较的是 数据值
s1.eq(s2)	 //结果是: false, 因为比较的是 地址值



逻辑运算符

运算符 功能解释
&& 逻辑与, 要求所有条件都满足(即: 结果为true), 简单记忆: 有false则整体为false.
|| 逻辑或, 要求只要满足任意一个条件即可, 简单记忆: 有true则整体为true.
! 逻辑非, 用来进行取反操作的. 即: 以前为true, 取反后为false, 以前为false, 取反后为true.

注意:

  1. 逻辑表达式不管简单还是复杂, 最终结果一定是Boolean类型的值, 要么是true, 要么是false.
  2. 在Scala代码中, 不能对一个Boolean类型的数据进行

    连续取反

    操作, 但是在Java中是可以的.

    • 即: !!false, 这样写会报错, 不支持这种写法.



位运算符

  1. 什么是进制
  2. 什么是8421码
  3. 整数的原码, 反码, 补码计算规则

注意:

​ 关于二进制的数据, 最前边的那一位叫: 符号位, 0表示正数, 1表示负数. 其他位叫: 数值位.

​ 例如: 0b10001001 结果就是一个: 负数, 0b00101010 结果就是一个: 正数.

所谓的原反补码, 其实指的都是二进制数据, 把十进制的数据转成其对应的二进制数据, 该二进制数据即为: 原码.

注意: 计算机底层存储, 操作和运算数据, 都是采用

数据的二进制补码形式

来实现的.

  • 正数

    • 正数的原码, 反码, 补码都一样, 不需要特殊计算.
  • 负数

    • 负数的反码计算规则: 原码的符号位不变, 数值位按位取反(以前为0现在为1, 以前为1现在为0)
    • 负数的补码计算规则: 反码 + 1

注意:

  1. 位运算符只针对于整型数据.
  2. 运算符操作的是数据的二进制补码形式.
  3. 小技巧: 一个数字被同一个数字位异或两次, 该数字值不变. 即: 10 ^ 20 ^ 20, 结果还是10
运算符 功能解释
& 按位与, 规则: 有0则0, 都为1则为1.
| 按位或, 规则: 有1则1, 都为0则为0.
^ 按位异或, 规则: 相同为0, 不同为1.
~ 按位取反, 规则: 0变1, 1变0.
<< 按位左移, 规则: 每左移一位, 相当于该数据乘2, 例如: 2 << 1, 结果为4
>> 按位右移, 规则: 每右移一位, 相当于该数据除2, 例如: 6 >> 1, 结果为3


案例case



已知有两个Int类型的变量a和b, 初始化值分别为10和20, 请写代码实现变量a和变量b的值的交换.

即最终结果为: a=20, b=10.

注意: 不允许直接写

a=20, b=10

这种代码.


  • 方式一: 通过算术运算符实现.

    //定义两个Int类型的变量a和b, 初始化值分别为10和20
    var a = 10
    var b = 20
    //将变量a和b的计算结果赋值给变量a
    a = a + b	//a = 30, b = 20
    //计算并赋值
    b = a - b	//a = 30, b = 10
    a = a - b	//a = 20, b = 10
    //打印结果
    println("a: " + a)		//a: 20
    println("b: " + b)		//b: 10
    

  • 方式二: 通过定义临时变量实现

    //定义两个Int类型的变量a和b, 初始化值分别为10和20
    var a = 10
    var b = 20
    //定义临时变量temp, 记录变量a的值
    var temp = a			//a = 10, b = 20, temp = 10
    //把变量b的值赋值给a
    a = b					//a = 20, b = 20, temp = 10
    //把临时变量temp的值赋值给b
    b = temp				//a = 20, b = 10, temp = 10
    //打印结果
    println("a: " + a)		//a: 20
    println("b: " + b)		//b: 10
    

  • 方式三: 通过位运算符实现

    //定义两个Int类型的变量a和b, 初始化值分别为10和20
    var a = 10
    var b = 20
    //定义临时变量temp, 记录变量a和b的位异或值(这个值不需要我们计算)
    var temp = a ^ b	//即: temp = 10 ^ 20
    //通过位异或进行交换变量值	
    a = a ^ temp		//运算流程: a = a ^ temp = a ^ a ^ b = 10 ^ 10 ^ 20 = 20
    b = b ^ temp		//运算流程: b = b ^ temp = b ^ a ^ b = 20 ^ 10 ^ 20 = 10
    //打印结果
    println("a: " + a)	//a: 20
    println("b: " + b)	//b: 10
    

在实际开发中, 我们要编写成千上万行代码, 代码的顺序不同, 执行结果肯定也会受到一些影响, 并且有些代码是满足特定条件才能执行的, 有些代码是要重复执行的. 那如何合理规划这些代码呢? 这就需要用到: 流程控制结构了。




  1. 掌握分支结构的格式和用法
  2. 掌握for循环和while循环的格式和用法
  3. 掌握控制跳转语句的用法
  4. 掌握循环案例
  5. 理解do.while循环的格式和用法

顺序结构,选择结构,循环结构。

if语句在使用时, 要注意的事项有以下三点:

  1. 和Java一样, 在Scala中, 如果大括号{}内的逻辑代码只有一行, 则大括号可以省略.
  2. 在scala中,条件表达式也是有返回值的
  3. 在scala中,没有三元表达式,可以使用if表达式替代三元表达式
  • scala中,使用{}表示一个块表达式
  • 和if表达式一样,块表达式也是有值的
  • 值就是最后一个表达式的值
val a = {
   println("1 + 1")
   1 + 1
}
println("a: " + a)

块的最后一行代码,作返回值进行返回。

循环


推荐使用for循环



简单循环

小括号写的是i <,后面写上数组/集合。先判断,然后决定是否执行。

for(i <- 表达式/数组/集合) {
    //逻辑代码
}

打印10次scala。

//定义一个变量, 记录1到10的数字
val nums = 1 to 10	//to是Scala中的一个关键字
//通过for循环, 打印指定的内容
for(i <- nums) {
     println("Hello, Scala! " + i)
}

简写为:

for(i <- 1 to 10) println("Hello, Scala! " + i)

大括号代码只有一行,可以省略不去,把代码合并为一行;



嵌套循环

和java一致。使用for表达式,打印以下字符, 每次只能输出一个”*”。

*****
*****
*****


步骤

  1. 使用for表达式打印3行,5列星星
  2. 每打印5个星星,换行


参考代码

//写法一: 普通写法
for(i <- 1 to 3) {		//外循环控制行数
    for(j <- 1 to 5) {	//内循环控制列数
        print("*")		//每次打印一个*
    }
    println()			//打印完一行(5个*)之后, 记得换行
}

//写法二: 压缩版
for(i <- 1 to 3) {		
    //这是两行代码
    for(j <- 1 to 5) if(j == 5) println("*") else print("*")
}

//写法三: 合并版
for(i <- 1 to 3; j <- 1 to 5) if(j == 5) println("*") else print("*")



守卫【掌握】

for表达式中,可以添加

if判断

语句,这个if判断就称之为守卫。我们可以使用守卫让for表达式更简洁。


写在小括号的if表达式


语法


当拿到i的值后,每个i都会执行if判断,当true以后,才会执行后面的逻辑代码:

for(i <- 表达式/数组/集合 if 表达式) {
    //逻辑代码
}


示例

使用for表达式打印1-10之间能够整除3的数字


参考代码

// 添加守卫,打印能够整除3的数字
for(i <- 1 to 10 if i % 3 == 0) println(i)



for推导式

在for表达式中,使用yield将循环中的某些数据进行返回。

Scala中的for循环也是有返回值的, 在for循环体中,可以使用yield表达式构建出一个集合(可以简单理解为: 就是一组数据),我们把使用yield的for表达式称之为

推导式.


示例

生成一个10、20、30…100的集合


参考代码

// for推导式:for表达式中以yield开始,该for表达式会构建出一个集合
// 这个for是有返回值的
val v = for(i <- 1 to 10) yield i * 10
println(v)



While

scala中while循环和Java中是一致的, 所以学起来非常简单。

格式

初始化条件
while(判断条件) {
    //循环体
    //控制条件
}

执行流程

  1. 执行初始化条件.
  2. 执行判断条件, 看其结果是true还是false.
  3. 如果是false则循环结束.
  4. 如果是true则执行循环体.
  5. 执行控制条件.
  6. 返回第二步, 重复执行.

示例

**需求: **

​ 打印1-10的数字


参考代码

//初始化条件
var i = 1
//判断条件
while(i <= 10) {
    //循环体
    println(i)
    //控制条件
    i = i + 1
}



do While【理解】

scala中do.while循环和Java中是一致的, 所以学起来非常简单。

先写初始化

格式

初始化条件
do{
    //循环体
    //控制条件
}while(判断条件) 

执行流程

  1. 执行初始化条件.
  2. 执行循环体.
  3. 执行控制条件.
  4. 执行判断条件, 看其结果是true还是false.
  5. 如果是false则循环结束.
  6. 如果是true则返回第2步继续执行.

注意:

  1. do.while循环不管判断条件是否成立, 循环体都会执行一次.
  2. for循环, while循环都是如果判断条件不成立, 则循环体不执行.

示例


需求

:

​ 打印1-10的数字


参考代码

//初始化条件
var i = 1
do{
    //循环体
    println(i)
    //控制条件
    i = i + 1
}while(i <= 10)	//判断条件



break,continue【掌握】

  • 在scala中,类似Java和C++的break/continue关键字被移除了,scala中没有break和continue
  • 如果一定要使用break/continue,就需要使用

    scala.util.control

    包下的Breaks类的

    breable



    break

    方法。

实现break


用法

  1. 导包.


    import scala.util.control.Breaks._

  2. 使用

    breakable

    将for表达式包起来

  3. for表达式中需要退出循环的地方,添加

    break()

    方法调用


示例

使用for表达式打印1-10的数字,如果遇到数字5,则退出for表达式


参考代码

// 导入scala.util.control包下的Break
import scala.util.control.Breaks._

breakable{
    for(i <- 1 to 10) {
        if(i == 5) break() else println(i)
    }
}

实现continue


用法

continue的实现与break类似,但有一点不同:

注意:

  1. 实现break是用breakable{}将整个for表达式包起来.
  2. 而实现continue是用breakable{}将for表达式的

    循环体

    包含起来就可以了.


示例

用for表达式打印1~10之间, 所有不能整除3的数字.

// 导入scala.util.control包下的Break    
import scala.util.control.Breaks._

for(i <- 1 to 100 ) {
    breakable{
        if(i % 3 == 0) break()
        else println(i)
    }
}



九九乘法表


需求

打印九九乘法表, 如下图:

在这里插入图片描述


步骤

  1. 通过外循环控制打印的行数.

  2. 通过内循环控制每行打印的列数.

    注意: 因为列数是随着行数递增的, 即:

    行数 该行的总列数
    1 1
    2 2
    3 3
    n n
    结论: 如果用

    i

    表示行数, 那么该行的列数取值范围为: [1, i]


参考代码


  • 方式一: 普通写法
//外循环控制行
for(i <- 1 to 9) {		
    //内循环控制列
    for(j <- 1 to i) {
        print(s"${i} * ${j} = ${i * j}\t")
    }
    println()			//别忘了换行
}

  • 方式二: 合并版写法
//外循环控制行
for(i <- 1 to 9; j <- 1 to i) {		
    print(s"${i} * ${j} = ${i * j}\t")
    if(j == i) println()	//别忘了换行
}



模拟登陆


需求

老王要登陆账号和密码来学习Scala, 假设老王的账号和密码分别为”dapeng”, “123”, 且同一账号只有3次登陆机会, 如果3次都录入错误, 则提示账号被锁定. 请用所学模拟该场景。


步骤

  1. 导包

    • scala.io.StdIn
    • scala.util.control.Breaks._
  2. 定义变量, 记录用户录入的账号和密码.
  3. 因为涉及到break的动作, 所以要用breakable{}把整个for表达式包裹起来
  4. 因为只有3次登陆机会, 所以推荐使用for循环.
  5. 提示用户录入他/她的账号和密码, 并接收.
  6. 判断用户录入的账号和密码是否正确.
  7. 如果录入正确, 则提示”登陆成功, 开始学习Scala!”, 循环结束.
  8. 如果录入错误, 则判断是否还有登陆机会

    • 有, 则提示”用户名或者密码错误, 您还有*次机会”, 然后返回第5步继续执行.
    • 没有, 则提示”账号被锁定, 请与管理员联系”, 循环结束.


参考代码

//1. 导包
import scala.io.StdIn
import scala.util.control.Breaks._

//2. 定义变量, 记录用户录入的账号和密码
var username = ""
var password = ""
//3. 因为涉及到break的动作, 所以要用breakable{}把整个for表达式包裹起来
breakable {
 	//4. 因为只有3次登陆机会, 所以推荐使用for循环.
    for(i <- 1 to 3) {
        //5. 提示用户录入他/她的账号和密码, 并接收.
        println("请录入您的账号: ")
        username = StdIn.readLine()
        println("请录入您的密码: ")
        password = StdIn.readLine()
        //6. 判断用户录入的账号和密码是否正确.
        if(username == "dapeng" && password == "123") {
            //7. 走到这里, 说明登陆成功, 循环结束.
            println("登陆成功, 开始学习Scala吧!")
            break()
        } else {
            //8. 走到这里, 说明登陆失败. 则判断是否还有登陆机会
            if(i == 3) println("账号被锁定, 请与管理员联系!") 
            else println(s"用户名或者密码错误, 您还有${3 - i}次机会")
        }
    }  
}




  1. 掌握方法的格式和用法
  2. 掌握函数的格式和用法
  3. 掌握九九乘法表案例

方法和Java中比较相似。不同的是:返回值类型推断,惰性方法。

java的方法和函数是一回事,scala的方法和函数是不同的。如何将方法转换为函数。

def 方法名(参数名:参数类型, 参数名:参数类型) : [return type] = {
    //方法体
}

注意:

  • 参数列表的参数类型不能省略
  • 返回值类型可以省略,由scala编译器自动推断
  • 返回值可以不写return,默认就是{}块表达式的值



简单方法


需求

:

  1. 定义一个方法getMax,用来获取两个整型数字的最大值, 并返回结果(最大值).
  2. 调用该方法获取最大值, 并将结果打印到控制台上.


参考代码

  • 方式一: 标准写法
//1. 定义方法, 用来获取两个整数的最大值.
def getMax(a:Int, b:Int): Int = {
    return if(a > b) a else b
}
//2. 调用方法, 获取最大值.
val max = getMax(10, 20)
//3. 打印结果.
println("max: " + max)
  • 方式二: 优化版
//1. 定义方法, 用来获取两个整数的最大值.
def getMax(a:Int, b:Int) = if(a > b) a else b
//2. 调用方法, 获取最大值.
val max = getMax(22, 11)
//3. 打印结果.
println("max: " + max)

方法体如果有一些值想方会,不需要写return。如果方法体就一行,大括号可以省略掉。



返回值的类型判断【掌握】

scala定义方法可以省略返回值的数据类型,由scala自动推断返回值类型。这样方法定义后更加简洁。

注意: 定义递归方法,不能省略返回值类型


示例

定义递归方法, 求5的阶乘.


步骤

  1. 定义方法factorial, 用来计算某个数字的阶乘

    规律: 1的阶乘等于1, 其他数字的阶乘为: n! = n * (n – 1)!

  2. 调用方法, 获取5的阶乘, 并将结果打印到控制台上.


参考代码

//1. 定义方法factorial, 用来计算某个数字的阶乘
def factorial(n:Int):Int = if(n == 1) 1 else n * factorial(n - 1)
//2. 调用方法, 获取5的阶乘.
val result = factorial(5)
//3. 将结果打印到控制台上.
println("result: " + result)



惰性方法【掌握】

当记录方法返回值的变量被声明为lazy时,

方法的执行将被推迟

,直到我们首次使用该值时, 方法才会执行, 像这样的方法, 就叫: 惰性方法。

注意:

  1. Java中并没有提供原生态的”惰性”技术, 但是可以通过特定的代码结构实现, 这种结构被称之为: 懒加载(也叫延迟加载)–单例设计模式懒汉式
  2. lazy不能修饰var类型的变量.,var修饰的变量会重新赋值,用lazy来修饰没有任何意义。


使用场景:

  1. 打开数据库连接

    由于表达式执行代价昂贵, 因此我们希望能推迟该操作, 直到我们确实需要表达式结果值时才执行它

  2. 提升某些特定模块的启动时间.

    `为了缩短模块的启动时间, 可以将当前不需要的某些工作推迟执行

  3. 确保对象中的某些字段能优先初始化

    为了确保对象中的某些字段能优先初始化, 我们需要对其他字段进行惰性化处理


需求

定义一个方法用来获取两个整数和, 通过”惰性”技术调用该方法, 然后打印结果.


参考代码

//1. 定义方法, 用来获取两个整数和
def getSum(a:Int, b:Int) = {
    println("getSum方法被执行了...")
    a + b
}
//2. 通过"惰性"方式调用该方法.
lazy val sum = getSum(1, 2)		//此时我们发现getSum方法并没有执行, 说明它的执行被推迟了.
// 第一次使用sum值时,sum才会执行。
//3. 打印结果, 并观察
println("sum: " + sum) 			//打印结果为sum: 3, 说明首次使用方法返回值时, 方法才会加载执行.



方法参数【掌握】

scala中的方法参数,使用比较灵活。它支持以下几种类型的参数:

  • 默认参数
  • 带名参数
  • 变长参数


默认参数

在定义方法时可以给参数定义一个默认值。


示例

  1. 定义一个计算两个整数和的方法,这两个值分别默认为10和20
  2. 调用该方法,不传任何参数


参考代码

//1. 定义一个方法, 用来获取两个整数的和
// 初始化变量x,y的默认值分别为10和20
def getSum(x:Int = 10, y:Int = 20) = x + y
//2. 通过默认参数的形式, 调用方法
val sum = getSum()
//3. 打印结果
println("sum: " + sum)


带名参数

在调用方法时,可以指定某些需要赋值的参数来赋值。


示例

  1. 定义一个计算两个整数和的方法,这两个值分别默认为10和20
  2. 调用该方法,只设置第一个参数的值


参考代码

//1. 定义一个方法, 用来获取两个整数的和
def getSum(x:Int = 10, y:Int = 20) = x + y
//2. 通过默认参数的形式, 调用方法
val sum = getSum(x=1)
//3. 打印结果
println("sum: " + sum)
// 同理因为1是第一个参数,所以也可以进行省略
val sum = getSum(1)


变长参数

如果方法的参数是不固定的,可以将该方法的参数定义成变长参数。

和java中的可变参数一致


语法格式:

def 方法名(参数名:参数类型*):返回值类型 = {
    //方法体
}

注意:

  1. 在参数类型后面加一个

    *

    号,表示参数可以是0个或者多个;
  2. 一个方法有且只能有一个变长参数, 并且变长参数要放到参数列表的最后边;

**示例一: **

  1. 定义一个计算若干个值相加的方法
  2. 调用方法,传入以下数据:1,2,3,4,5


参考代码

//1. 定义一个计算若干个值相加的方法
def getSum(a:Int*) = a.sum
//2. 调用方法,传入一些整数, 并获取它们的和
val sum = getSum(1,2,3,4,5)
//3. 打印结果
println("sum: " + sum)
val sum2 = getSum()
// sum2结果为0



调用方式【掌握】

在scala中,有以下几种方法调用方式:

  • 后缀调用法
  • 中缀调用法
  • 花括号调用法
  • 无括号调用法

注意: 在编写spark、flink程序时,会经常使用到这些方法调用方式。



后缀调用法

这种方法与Java没有区别。


语法

对象名.方法名(参数)


示例

使用后缀法调用

Math.abs

, 用来求绝对值


参考代码

//后缀调用法
Math.abs(-1)	//结果为1

后缀调用法,涉及到了一对小括号。当调用的方式多时,就容易出现混淆的情况。



中缀调用法


语法

对象名 方法名 参数

例如:

1 to 10


注意: 如果有多个参数,使用括号括起来


示例

使用中缀法调用

Math.abs

, 用来求绝对值

//中缀调用法
Math abs -1		//结果为1


扩展: 操作符即方法

来看一个表达式, 大家觉得这个表达式像不像方法调用?

1 + 1

通过中缀调用法在调用+这个方法。

在scala中,+ – * / %等这些操作符和Java一样,但在scala中,


  • 所有的操作符都是方法
  • 操作符是一个

    方法名字是符号的方法



花括号调用法

语法

Math.abs{ 
    // 表达式1
    // 表达式2
}

注意:

方法只有一个参数

,才能使用花括号调用法


示例

使用花括号调用法

Math.abs

求绝对值


参考代码

//花括号调用法
Math.abs{-10}	//结果为: 10


无括号调用法

如果方法没有参数,可以省略方法名后面的括号


示例

  • 定义一个无参数的方法,打印”Hello, Scala!”
  • 使用

    无括号调用法

    调用该方法


参考代码

//1. 定义一个无参数的方法,打印"Hello, Scala!"
def sayHello() = println("Hello, Scala!")
// 无返回值的方法是Unit

//2. 调用方法
sayHello

注意:

  1. 在Scala中, 如果方法的返回值类型是

    Unit类型

    , 这样的方法称之为

    过程(procedure)

  2. 过程

    的等号(=)可以省略不写. 例如:
def sayHello() = println("Hello, Scala!")   
//可以改写为
def sayHello() { println("Hello, Scala!") }	 //注意: 这个花括号{}不能省略



函数入门

scala支持函数式编程。



定义函数


语法

val 函数变量名 = (参数名:参数类型, 参数名:参数类型....) => 函数体

注意:

  • 在Scala中, 函数是一个

    对象

    (变量),可以赋值给变量
  • 类似于方法,函数也有参数列表和返回值
  • 函数定义不需要使用

    def

    定义
  • 无需指定返回值类型

scala的函数和方法不是一回事,java中是相同的。



示例

**需求: **

  1. 定义一个计算两个整数和的函数
  2. 调用该函数


参考代码

//1. 定义一个用来计算两个整数和的函数, 并将其赋值给变量sum
// (x:Int, y:Int) => x + y是一个函数,在scala中,函数是可以通过变量来接收
val getSum = (x:Int, y:Int) => x + y
//2. 调用函数.
val result = getSum(1,2)
//3. 打印结果
println("result: " + result)



方法和函数的区别【掌握】

在Java中, 方法和函数之间没有任何区别, 只是叫法不同. 但是在Scala中, 函数和方法就有区别了, 具体如下:


  • 方法是隶属于类或者对象

    的,在运行时,它是

    加载到JVM的方法区

  • 可以将函数对象赋值给一个变量,在运行时,它是

    加载到JVM的堆内存

    中(对象是加载到堆内存)
  • 函数是一个对象,继承自FunctionN,函数对象有apply,curried,toString,tupled这些方法。方法则没有

结论: 在Scala中,

函数是对象, 而方法是属于对象的

, 所以可以理解为:

方法归属于函数.


示例

演示方法无法赋值给变量

// 定义函数并赋值给对象
val getSum = (a:Int, b:Int) => a+b
//1. 定义方法
def add(x:Int,y:Int)= x + y

//2. 尝试将方法赋值给变量.
//val a = add(1, 2)		//不要这样写, 这样写是在"调用方法", 而不是把方法赋值给变量
val a = add

//3. 上述代码会报错
<console>:12: error: missing argument list for method add
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `add _` or `add(_,_)` instead of `add`.
       val a = add



方法转换为函数

有时候需要将方法转换为函数. 例如: 作为变量传递,就需要将方法转换为函数


格式

val 变量名 = 方法名 _		//格式为: 方法名 + 空格 + 下划线

注意: 使用

_

即可将方法转换为函数


示例

  1. 定义一个方法用来计算两个整数和
  2. 将该方法转换为一个函数,并赋值给变量


参考代码

//1. 定义一个方法用来计算两个整数和
def add(x:Int, y:Int)= x + y
//2. 将该方法转换为一个函数,并赋值给变量
val a = add _
//3. 调用函数, 用来获取两个整数的和,可以直接进行调用
val result = a(1, 2)
//4. 打印结果
println("result: " + result)

方法和函数的区别:方法运行时JVM的区域不同。



nn乘法表


需求


定义方法实现, 根据用户录入的整数, 打印对应的乘法表。

例如: 用户录入5,则打印55乘法表,用户录入9,则打印99乘法表。


目的

  1. 考察

    键盘录入和方法, 函数

    的综合运用.
  2. 体会方法和函数的不同.


步骤

  1. 定义方法(或者函数), 接收一个整型参数.
  2. 通过for循环嵌套实现, 根据传入的整数, 打印对应的乘法表.
  3. 调用方法(函数), 输出结果.


参考代码

  • 方式一: 通过方法实现
//1. 定义一个方法, 接收一个整型参数.
def printMT(n:Int) = {   //Multiplication Table(乘法表)
    //2. 通过for循环嵌套实现, 根据传入的整数, 打印对应的乘法表.
    for(i <- 1 to n; j <- 1 to i) {
    	print(s"${j} * ${i} = ${j * i}\t"); 
        if(j==i) println()
    }
}
//3. 调用方法
printMT(5)

//优化版: 上述定义方法的代码可以合并为一行(目前只要能看懂即可)
// 通过\r\n来实现println的功能
/*def printMT(n:Int) = for(i <- 1 to n; j <- 1 to i) print(s"${j} * ${i} = ${j * i}" + (if(j==i) "\r\n" else "\t"))*/
  • 方式二: 通过函数实现
//1. 定义一个函数, 接收一个整型参数.
val printMT = (n:Int) => {
    //2. 通过for循环嵌套实现, 根据传入的整数, 打印对应的乘法表.
    for(i <- 1 to n; j <- 1 to i) {
    	print(s"${j} * ${i} = ${j * i}\t"); 
        if(j==i) println()
    }
}
//3. 调用函数
printMT(9)

//优化版: 上述定义函数的代码可以合并为一行(目前只要能看懂即可)
/*val printMT = (n:Int) => for(i <- 1 to n; j <- 1 to i) print(s"${j} * ${i} = ${j * i}" + (if(j==i) "\r\n" else "\t"))*/




  1. 掌握类和对象的定义
  2. 掌握访问修饰符和构造器的用法
  3. 掌握main方法的实现形式
  4. 掌握伴生对象的使用
  5. 掌握定义工具类的案例



类和对象【了解】

Scala是一种函数式的面向对象语言, 它也是支持面向对象编程思想的,也有类和对象的概念。我们依然可以基于Scala语言来开发面向对象的应用程序。



相关概念

什么是面向对象?

面向对象是一种编程思想, 它是基于面向过程的, 强调的是以对象为基础完成各种操作.

面向对象的三大思想特点是什么?

1. 更符合人们的思考习惯.
2. 把复杂的事情简单化.
3. 把程序员从执行者变成指挥者.

面试题: 什么是面向对象? 思路:

概述, 特点, 举例, 总结

,从这四个方面回答

什么是类?

类是属性和行为的集合, 是一个抽象的概念, 看不见, 也摸不着.
  • 属性(也叫成员变量): 名词, 用来描述事物的外在特征的.

  • 行为(也叫成员方法): 动词, 表示事物能够做什么.

  • 例如: 学生有姓名和年龄(这些是属性), 学生要学习, 要吃饭(这些是行为).

什么是对象?

对象是类的具体体现, 实现. 

面向对象的三大特征是什么?

封装, 继承, 多态.



创建类和对象

Scala中创建类和对象可以通过class和new关键字来实现.

用class来创建类, 用new来创建对象.

示例

创建一个Person类,并创建它的对象, 然后将对象打印到控制台上.

步骤

  1. 创建一个scala项目,并创建一个object类

    注意: object修饰的类是单例对象, 这点先了解即可, 稍后会详细解释.

  2. 在object类中添加main方法.

  3. 创建Person类, 并在main方法中创建Person类的对象, 然后输出结果.



版权声明:本文为qq_29027865原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。