Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。
1)Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。(多范式,就是多种编程方法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法。)
2)Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有的Java类库,实现两种语言的无缝接。
3)Scala单作为一门语言来看,非常的简洁高效。
4)Scala在设计时,马丁·奥德斯基是参考了Java的设计思想,可以说Scala是源Java,同时马丁·奥德斯基也加入了自己的思想,将函数式编程语言的特点融合到JAVA中。
package com.xiaoming
object Scalademo1 {
def main(args: Array[String]): Unit = {
println("Hello Scala")
}
}
//Scala完全面向对象,故Scala去掉了Java中非面向对象的元素,如static关键字,void类型
//
1)static
Scala无static关键字,由object实现类似静态方法的功能(类名.方法名),class关键字和Java中的class关键字作用相同,用来定义一个类;
2)void
对于无返回值的函数,Scala定义其返回值类型为Unit类
(1)单行注释://
(2)多行注释:/* */
(3)文档注释
def main(args: Array[String]): Unit = {
println("Hello Scala")
println(i)
//(1)单行注释://
println("xiaoming")
//(2)多行注释:/* */
/*
println("xiaoming")
println("mingshao")
*/
//(3)文档注释:/**
//*
//*/
/**
* println("xiaoming")
* println("xiaoming")
* println("xiaoming")
*/
1)回顾:Java 变量和常量语法
变量类型 变量名称 = 初始值 int a = 10
final 常量类型 常量名称 = 初始值 final int b = 20
2)基本语法
var 变量名 [: 变量类型] = 初始值
val 常量名 [: 常量类型] = 初始值
注意:能用常量的地方不用变量
var i:Int = 10 //var修饰 可变
val j:Int = 20 //val修饰 不可变
i = 20 //正确写法
j = 30 //错误写法
注意: var 修饰的对象引用可以改变,val 修饰的对象则不可改变,但对象的状态(值)
却是可以改变的。(比如:自定义对象、数组、集合等等)
object TestVar {
def main(args: Array[String]): Unit = {
// p1 是 var 修饰的,p1 的属性可以变,而且 p1 本身也可以变
var p1 = new Person()
p1.name = "xiaoming"
p1 = null
// p2 是 val 修饰的,那么 p2 本身就不可变(即 p2 的内存地址不能变),
//但是,p2 的属性是可以变,因为属性并没有用 val 修饰。
val p2 = new Person()
p2.name = "mingshao"
// p2 = null // 错误的,因为 p2 是 val 修饰的
}
}
class Person {
var name: String = "mingshao"
}
Java基本数据类型:char、byte、short、int、long、float、double、boolean
Java引用类型:(对象类型)
由于Java有基本类型,而且基本类型不是真正意义的对象,即使后面产生了基本类型的包装类,但是仍然存在基本数据类型,所以Java语言并不是真正意思的面向对象。
Java基本类型的包装类:Character、Byte、Short、Integer、Long、Float、Double、Boolean
注意:Java中基本类型和引用类型没有共同的祖先。
1)Scala中一切数据都是对象,
都是Any的子类
。
2)Scala中数据类型分为两大类:数值类型(AnyVal)、引用类型(AnyRef),不管是值类型还是引用类型都是对象。
3)Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)
4)Scala中的StringOps是对Java中的String增强
5)Unit:对应Java中的void,用于方法返回值的位置,表示方法没有返回值。Unit是 一个数据类型,只有一个对象就是()
。Void不是数据类型,只是一个关键字
6)Null是一个类型,只 有一个对 象就 是null。它是所有引用类型(AnyRef)的子类。
7)Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数。
整型(Byte [1]、Short [2]、Int [4]、Long [8])
val byte: Byte = 127
val short: Short = 10
val int: Int = 20
val long: Long = 123456879L
浮点类型(Float [4]、Double [8])
val float: Float = 127.123f
val short: Double = 123.123
//Scala 的浮点型常量默认为 Double 型,声明 Float 型常量,须后加‘f’或‘F’。
字符类型(char)
//(1)字符常量是用单引号 ' ' 括起来的单个字符。
val c1: Char = 'a'
println(c1)
//(2)\t :一个制表位,实现对齐的功能
println("姓名\t 年龄")
//(3)\n :换行符
println("西门庆\n 潘金莲")
//(4)\\ :表示\
println("c:\\岛国\\avi")
//(5)\" :表示"
println("同学们都说:\"大海哥最帅\"")
布尔类型
object TestBooleanType {
def main(args: Array[String]): Unit = {
var isResult : Boolean = false
var isResult2 : Boolean = true
}
}
字符串操作
object demo3 {
def main(args: Array[String]): Unit = {
val builder: StringBuilder = new StringBuilder()
val str1: String = "abcd"
val str2: String = "def"
//这里‘.’可加可不加
builder.append("abcd")
builder.append(",")
builder.append("efg")
println(builder)
//scala方式 进行连接字符串
println(s"${str1}${str2}")
val str3: String = "123"
val int3: Int = Integer.parseInt(str3)
println(int3)
val int = str3.toInt
println(int)
val strN: String = "1,2,3,4,5,6,7,8,9"
//split切分并转成list
val list: List[String] = strN.split(",").toList
//遍历list
for (str<-list){
print(str)
}
//在Scala中采取函数式编程思想进行遍历
list.foreach(print)
}
}
}
package com.xiaoming
import java.sql.{Connection, DriverManager, PreparedStatement, ResultSet}
object demo3 {
def main(args: Array[String]): Unit = {
//链接mysql
//创建链接
val conn: Connection = DriverManager.getConnection("jdbc:mysql://master:3306/student","root","123456")
//创建statement
val st: PreparedStatement = conn.prepareStatement("select * from student where clazz=?")
//设置参数
st.setString(1,"理科一班")
//执行
val rs: ResultSet = st.executeQuery()
while (rs.next()){
val id: Int = rs.getInt("id")
val name: String = rs.getString("name")
val clazz: String = rs.getString("clazz")
val gender: String = rs.getString("gender")
val last_mod: String = rs.getString("last_mod")
val age: Int = rs.getInt("age")
println(s"${id},${name},${age},${gender},${clazz},${last_mod}")
}
}
}
package com.xiaoming
/**
* 面向对象:封装、继承、多态
* 类中可以定义:属性、方法
* {}就是默认的构造方法
*/
class StudentScala(id: String, name: String, age: Int) {
println("调用了默认的构造方法")
// 定义类的属性 定义即赋值
val _id: String = id
val _name: String = name
val _age: Int = age
// 重写了父类的方法
override def toString:String = s"StudentScala(${_id}, ${_name}, ${_age})"
//重载构造方法
// def this(id:String,name:String,age:Int){
// this(id,name,age)
// println("调用了新的构造方法")
// }
}
object DemoStudent{
def main(args: Array[String]): Unit = {
val stu1: StudentScala = new StudentScala("001","小明",24)
println(stu1)
}
}
继承
package com.xiaoming
class A(id: String, name: String) {
val _id: String = id
val _name: String = name
override def toString = s"A(_id=${_id}, _name=${_name})"
def printAB(): Unit = {
println("这是A的对象方法")
}
}
class B(id: String, name: String, age: Int, clazz: String) extends A(id, name) {
val _age: Int = age
val _clazz: String = clazz
override def toString = s"B(_id=${_id},_name=${_name},_age=${_age}, _clazz=${_clazz})"
override def printAB(): Unit = {
println("这是B的对象方法")
}
}
object Demo4obj {
def printTwice(a: A): Unit = {
a.printAB()
a.printAB()
}
def main(args: Array[String]): Unit = {
val a: A = new A("001", "张三")
val b: B = new B("002", "李四", 21, "文科一班")
println(a._id)
println(a._name)
println(a)
println(b._id)
println(b._name)
println(b._age)
println(b._clazz)
println(b)
a.printAB()
b.printAB()
printTwice(b) // 多态 父类引用指向子类对象
printTwice(a)
// 样例类
val caseStu: Demo5CaseClass = new Demo5CaseClass("003", "小明", 22, "男", "理科三班")
}
}
样例类
package com.xiaoming
// 样例类
// 在样例类中定义的参数 默认由val修饰 不可以改变
// 如果需要对属性重新赋值 则需要在定义的时候 加上 var修饰
// 会自动实现get set(针对var修饰的属性)方法,还会实现序列化接口(可以在网络中进行传输)
case class CaseClassDemo2(val id: String, name: String, age: String, gender: String, clazz: String)
object Demo2 {
def main(args: Array[String]): Unit = {
// 创建样例类的对象
// new关键字可以省略
val stu: CaseClassDemo2 = CaseClassDemo2("002", "小明", "24", "男", "理科1班")
println(stu.id)
println(stu.name)
println(stu.age)
println(stu.gender)
println(stu.clazz)
}
}
1)面向对象编程
解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题。
对象:用户
行为:登录、连接 JDBC、读取数据库
属性:用户名、密码
Scala 语言是一个完全面向对象编程语言。万物皆对象
对象的本质:对数据和行为的一个封装
2)函数式编程
解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用
这些封装好的步骤,解决问题。
例如:请求->用户名、密码->连接 JDBC->读取数据库
Scala 语言是一个完全函数式编程语言。万物皆函数。
函数的本质:函数可以当做一个值进行传递
3)在 Scala 中函数式编程和面向对象编程完美融合在一起了。
(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
(2)如果函数体只有一行代码,可以省略花括号
(3)返回值类型如果能够推断出来,那么可以省略( : 和 返回值类型*一起省略)
(4)如果有 return,则不能省略返回值类型,必须指定
(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
(6)Scala 如果期望是无返回值类型,可以省略等号
(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
object TestFunction {
/**
* def 这是一个函数
* f 函数名
* s: String 函数的参数
* Unit: 函数的返回值类型,这里相当于void
* {} : 方法体
*/
def main(args: Array[String]): Unit = {
//(0)函数标准写法
def f(s: String): String = {
return s + " jinlian"
}
println(f("Hello"))
// 至简原则:能省则省
//(1) return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
def f1(s: String): String = {
s + " jinlian"
}
println(f1("Hello"))
//(2)如果函数体只有一行代码,可以省略花括号
def f2(s: String): String = s + " jinlian"
//(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
def f3(s: String) = s + " jinlian"
println(f3("Hello3"))
//(4)如果有 return,则不能省略返回值类型,必须指定。
def f4(): String = {
return "ximenqing4"
}
println(f4())
//(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
def f5(): Unit = {
return "dalang5"
}
println(f5())
//(6)Scala 如果期望是无返回值类型,可以省略等号
// 将无返回值的函数称之为过程
def f6() {
"dalang6"
}
println(f6())
//(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
def f7() = "dalang7"
println(f7())
println(f7)
//(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def f8 = "dalang"
//println(f8())
println(f8)
//(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
def f9 = (x:String)=>{println("wusong")}
def f10(f:String=>Unit) = {
f("")
}
f10(f9)
println(f10((x:String)=>{println("wusong")}))
}
}
package com.xiaoming
object demo7Fuc2 {
def main(args: Array[String]): Unit = {
/**
* 函数式编程(高阶函数、面向函数编程)
* 面向对象编程:把对象传来传去 注意在将对象传给函数的时候有类型的限制 以及 对象作为返回值的时候也有类型的限制
* 面向函数编程:把函数传来传去 注意在将函数传给函数的时候有类型的限制 以及 函数作为返回值的时候也有类型的限制
*
* 函数式编程的分类:
* 1、以函数作为参数
* 2、以函数作为返回值
*
* 怎么去描述函数的类型?
* 1、跟def关键字无关
* 2、跟函数名也无关
* 3、跟函数实现的功能也无关
* 4、跟函数的参数名称也无关
* 5、实际上函数的类型 由参数的类型(个数、顺序)及返回值的类型共同决定
* 参数的类型 => 返回值的类型
*/
println(func1("100"))
println(func2(200))
println(funcX(func1))
// 调用"匿名函数"
println(ff("100", 4))
// 如果函数逻辑比较简单 可以使用匿名函数进行简化
println(funcX((str: String) => {str.toInt + 5})) // 205
/**
* 匿名函数的省略规则:
* 1、函数体只有一行代码,花括号可以省略
* 2、如果匿名函数作为另一个函数的参数传入 参数的类型可以省略
* 3、如果参数只有一个 括号可以省略
* 4、如果参数只被使用的一次 则可以省略 并用下划线_替代
*/
println(funcX((str: String) => str.toInt + 6)) // 206
println(funcX((str) => str.toInt + 6)) // 206
println(funcX(str => str.toInt + 7)) // 207
println(funcX(_.toInt + 8)) // 208
}
def func1(str: String) = str.toInt + 1
def func2(i: Int) = i + 3
def funcX(f: String => Int): Int = {
val i: Int = f("200")
i
}
//匿名函数
(str1: String, str2: Int) => str1.toInt + str2
// 匿名函数也可以拥有名字
// 函数类型 =》返回值类型
val ff: (String, Int) => Int = (str1: String, int1: Int) => {
str1.toInt + int1
}
}
数组遍历(map、foreach方法)
package com.xiaoming
object demo8Func3 {
def main(args: Array[String]): Unit = {
//创建一个数组
val array: Array[Int] = Array[Int](1, 2, 3, 4, 5, 6, 7, 8)
//遍历
var index: Int = 0
while (index < array.length) {
println(array(index))
index += 1
}
// 让每一个array中的元素扩大两倍
var index2: Int = 0
while (index2 < array.length) {
array(index2) = array(index2) * 2
// println(array(index2))
index2 += 1
}
println(array.mkString(","))
// Scala的思想
// foreach方法:需要传入一个函数f:参数类型为Int,返回值类型为Unit
// foreach方法会将array中的每一个元素依次作为参数传递给函数f
// println是一个函数:参数类型为Any,返回值类型为Unit
// 遍历
array.foreach(println)
println("*" * 50)
//其他遍历方式
for (elem <- array) {
println(elem)
}
println("*" * 50)
for (i <- 0 to array.length - 1) {
println(array(i))
}
for (i <- Range(0, array.length)) {
println(array(i))
}
for (i <- 0 until array.length) {
println(array(i))
}
// map方法接收一个函数f:参数为Int类型(与array中每个元素的类型有关),返回值类型任意(自己定义)
// map方法同foreach方法的差异在于有没有返回值
def extend2(int: Int): String = {
(int * 2).toString
}
// map方法会将array中的每一个元素作为参数传给函数f,最后会将变换后的结果作为新的数组返回
val array2: Array[String] = array.map(extend2)
println(array2.mkString(","))
//使用匿名函数简化
println(array.map(_ * 2).mkString(","))
}
}