class User {
// 伴生类
}
object User {
// 伴生对象
def apply() = new User() // 构造伴生类对象
}
...
val user1 = new User()// 通过构造方法创建对象
Val user2 = User.apply() // 通过伴生对象的apply方法构造伴生类对象
val user3 = User() // scala编译器省略apply方法,自动完成调用
HelloWorld案例
object Scala01_HelloWorld {
/*
1. object 是执行程序的一个固定写法
java :
class Test {
public String name = "zhangsan";
public static void main( String[] args ) {
}
}
2. object 后面紧接着的是类名,类似于java中class
3. def : scala语言中声明方法的关键字
4. main : 其实就是执行的主程序方法, 如果名称发生变化,那么程序无法执行
5. 小括号 : 方法名后面跟着的小括号表示参数列表
6. args: Array[String] => 声明参数
java : String[] args
scala : args: Array[String]
java是一个强类型语言,更看重类型,所以需要直接了当,先声明类型
scala 认为在开发中应该更关注名称,而不是类型,所以名称应该放置在前,一目了然。
先声明名称,再声明类型,中间使用冒号隔开。
7. Array[String]
在scala语法中表示数组
java并不是完全面向对象的语言,所以其中包含了很多不是面向对象的语法
基本类型,静态,数组
scala语言是基于java语言开发的,所以是完全面向对象的语言。
所以数组也有自己的类型。
[]表示泛型,String就表示数组中存放数据的类型
8. main() : Unit
java : void main() => 方法的返回值类型 方法名称(参数列表)
scala : main() : Unit => 方法名称(参数列表): 方法的返回值类型
void 在java中表示方法没有返回值。但是它是一个关键字。不是类型
scala是完全面向对象的语言, void采用Unit类型来代替。也表示没有返回值
9. 等号 :赋值
将一段逻辑赋值给方法,那么方法在执行时就可以执行逻辑。
10. System.out.println("Hello Scala")
scala语言是基于java语言开发的,所以在scala代码中可以直接调用java的api
java中的类库可以直接在scala中使用
11. println("Hello Scala")
scala中有很多自己的语法
a. println(打印)
b. 代码的结束没有使用分号结尾
scala语言认为很多不必要的操作是可以省略了,由编译器决定是否允许省略。
scala认为代码只要换行了,就表示两段不同的逻辑,所以不需要分号也可以识别出来。
如果将两段逻辑放置在一行中,但是没有使用分号分隔开,那么编译器无法正确识别,会发生错误。
这个时候,就应该显示地增加分号。
*/
// 类的主体内容
def main(args: Array[String]): Unit = {
// 方法的主体内容
//new java.util.ArrayList();
System.out.println("Hello Scala")
println("Hello Scala")
}
}
object Scala03_HelloJava {
/*
1. scala要想执行,也需要编译成class文件,如果平台不变,scala编译后的字节码文件
应该和java编译的字节码文件的规则一样。
java : public static void main => XXXXXXX
scala : def main : Unit => XXXXXXX
2. classpath : 类路径(类文件的存放路径)
windows dos 窗口:以当前的位置作为classpath
idea : 项目基于maven创建的,所以classpath遵循maven的规则,在target/classes目录中
idea展示class文件时,采用特殊的方式。
3. scala的程序在编译后会产生两个class文件
第一个class文件 : 当前类名 + .class
第二个class文件 : 当前类名 + $ + .class,使用object关键字声明的类文件
使用class关键字声明类,会产生当前类的class文件
使用object关键字声明类,会产生当前类的class文件和一个特殊的class文件
4. 如果向查看class文件
a. 使用javap工具可以查看字节码文件
b. 可以使用反编译工具 : class => java
b.1 第三方工具 : jd-gui.exe
b.2 IDEA自带的反编译工具 : 右键点击类文件 => Decompile Scala to Java
5. 通过反编译,可以看到,生成的字节码文件中其实包含了如下内容
a. public static void main( String[] args )
b. a = new 当前类$.class 对象
c. a.main => 调用scala中main方法
d. 在scala的main方法中调用了代码:System.out.println("Hello Java")
*/
def main( args : Array[String] ) : Unit = {
System.out.println("Hello Java")
println("Hello Java")
}
// scala中变量必须显示的初始化,不能省略
var name:String = "zhangsan"
def main(args: Array[String]): Unit = {
// Scala语言中有一个非常重要的原则
// 至简原则 : 能省则省
// Java是一个强类型的语言,而scala基于java开发,所以也是强类型语言
// 变量声明的类型和变量的取值类型应该是一致的。
// Scala中可以省略变量的类型
//val name : String = "zhangsan"
// 编译器发现变量的取值为字符串类型,那么从语法角度来讲,name就应该是字符串类型
// 所以即使name变量不声明String类型,编译器也能自动添加String类型,保证编译通过。
// 这个操作,称之为编译器的自动识别(自动推断)
val name = "zhangsan"
println(name)
}
def main(args: Array[String]): Unit = {
// val s1 : String = "abc"
// val s2 : String = "abc"
//
// println(s1 == s2) // true
// println(s1.equals(s2)) // true
val s3 : String = new String("abc")
//val s3 : String = null
val s4 : String = new String("abc")
// Scala语言 中的双等号的作用其实进行了非空校验后进行equals操作
// 所以 双等号不用于内存的比较
//println(s3 == s4) // true
//println(s3.equals(s4)) // true
// 如果scala中想比较对象的内存地址
// Scala中eq操作在编译时会编译为java中的双等号,所以才是真正地比较内存地址
println(s3 eq s4)
// TODO Scala中比较对象的内容使用 双等号
// TODO Scala中比较对象的内存使用 eq
}
}
public static void main(String[] args) {
// 判断字符串是否非空。如果不为空,返回true,如果为空,返回false
// 字符串如果为null,表示空,如果为空字符串,也为空。
// & : 逻辑与, 所有条件都会判断执行
// && : 短路与, 如果第一个条件为false,逻辑短路,不会向后执行,直接返回结果
String s = null;
boolean flg = isNotEmpty(s);
System.out.println(flg);
}
private static boolean isNotEmpty( String s ) {
return s != null && !s.equals("");
}
break
import scala.util.control.Breaks
object Scala11_Flow_Break {
def main(args: Array[String]): Unit = {
// Scala中没有break关键字。
// break语法比较单一,并且不是面向对象,null, void
// Scala采用面向对象的语法代替break关键字。
var age = 10
Breaks.breakable {
while ( age < 20 ) {
if ( age == 15 ) {
// 跳出循环
// break方法会抛出异常,会中止程序的运行
Breaks.break()
}
println("age = " + age )
age += 1
}
}
println("main方法。。。")
}
}
import scala.util.control.Breaks._
object Scala12_Flow_Break1 {
def main(args: Array[String]): Unit = {
// Scala中没有break关键字。
// break语法比较单一,并且不是面向对象,null, void
// Scala采用面向对象的语法代替break关键字。
// Scala 中没有continue关键字,也不存在对应的语法
var age = 10
breakable {
while ( age < 20 ) {
if ( age == 15 ) {
// 跳出循环
// break方法会抛出异常,会中止程序的运行
break
}
println("age = " + age )
age += 1
}
}
println("main方法。。。")
}
}
函数式编程
object Scala02_Function1 {
def main(): Unit = {
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程
// 函数 & 方法
// 函数的概念来自于Scala
// 方法的概念来自于Java
// Scala是完全面向函数式编程语言,所以方法其实就是函数
// 一般情况下,将类中封装的功能函数称之为方法
// 其他地方封装的功能就称之函数
// 函数可以声明在任意的地方
// 方法中可以声明函数
// 函数中不能声明方法,因为方法只能在类中声明
// TODO 类中的函数就是方法,所以符合java中方法的语法规则: 重写 & 重载
// TODO 函数没有重写和重载的概念
def test(): Unit = {
println("test...")
}
// def test( s : String ): Unit = {
// println("test...")
// }
test()
}
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 普通难度
// TODO 函数参数是不是可以无限多?
// 函数的参数不能超过22个,如果超过22个,可以声明和使用,但是不能给别人用。
// TODO 如果想要传递很多的参数,那么可以将参数的类型设定为集合类型或变为可变类型
// 可变参数, java中使用..., 参数可能有,可能没有。
// scala中使用星号*
// 如果使用可变参数时,不传递这个参数,那么获取到的是空集合List()
// 如果使用可变参数时,传递这个参数,那么获取到的是包装数组,数组中就是每一个参数
def fun2( name : String* ): Unit = {
println(name)
}
// fun2()
// fun2("zhangsan")
// fun2("zhangsan", "lisi", "wangwu")
// TODO 可变参数应该放置在参数列表的最后
// 参数列表中不应该有多个可变参数,就一个,而且放置在参数列表的最后
def fun3( age : Int, name : String*): Unit = {
println(name)
}
//fun3(20, "zhangsan", "lisi", "wangwu")
// TODO 改变参数
// Scala中函数的参数不能改,使用val声明
// 如果想要给函数的参数提供默认值,scala可以在参数的后面直接增加默认值
def regUser( account : String, password : String = "123123" ): Unit = {
// if ( password == null ) {
// // password = "123123"
// }
println(s"account : $account, password : $password")
}
// 如果参数中有默认值,那么在调用时,可以不传递这个参数,那么会使用默认值
regUser("zhangsan")
// 如果参数中有默认值,那么在调用时,传递这个参数,那么会覆盖默认值
regUser("zhangsan", "000000")
def regUser1( account : String, password : String = "123123", tel : String ): Unit = {
// if ( password == null ) {
// // password = "123123"
// }
println(s"account : $account, password : $password, tel : $tel")
}
// 函数的参数在调用时的匹配规则为从左到右依次匹配。
// Scala提供了一种语法来解决参数默认值调用的问题
// TODO 带名参数传递
// 可以改变参数传递的顺序
regUser1(tel = "13312341234", account = "wangwu")
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 噩梦难度
// Scala中函数有至简原则 : 能省则省
// 这里的能省则省,必须是编译器可以自动推断的场合,才能省
def fun1( name : String ): String = {
return "Name : " + name
}
// TODO 1. 当函数需要返回值的时候,可以采用函数体中的满足条件的最后一行代码作为返回值
// 所以可以省略return关键字
def fun2( name : String ): String = {
"Name : " + name
}
//println(fun2("zhangsan"))
// TODO 2. 如果编译器能够推断出函数的返回值类型,那么返回值类型可以省略
def fun3( name : String ) = {
"Name : " + name
}
def fun33( name : String ) = {
val age = 20
if ( age == 20 ) {
//"Name : " + name
1.0
} else {
"name"
}
}
// println(fun33("zhangsan"))
// TODO 3. 如果函数体逻辑代码只有一行,那么大括号可以省略
def fun4( name : String ) = "Name : " + name
//println(fun4("lisi"))
// TODO 4. 如果当前函数的参数列表没有参数的情况,那么小括号可以省略
def fun5() = "wangwu"
//println(fun5())
// 如果函数的参数只有一个或没有,那么调用这个函数时,小括号可以省略
// 1 + 1
//println(fun5)
def fun55 = "wangwu"
val name = "zhangsan"
// TODO 如果函数省略了参数列表的小括号,那么在调用时就不能使用小括号
// 统一访问原则
println(fun55)
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 噩梦难度
// Scala中函数有至简原则 : 能省则省
// 这里的能省则省,必须是编译器可以自动推断的场合,才能省
def fun1(): Unit = {
return "zhangsan"
}
// TODO 如果函数明确声明返回值类型为Unit,那么即使函数体中有return关键字也不起作用
//println(fun1())
// TODO 如果函数体中存在return语句,那么返回值类型不能省略
def fun2() : Unit = {
return "zhangsan"
}
// TODO 如果函数返回值类型为Unit,并且想要省略Unit关键字,可以采用特殊的方式
// 可以将等号省略掉,表示这个函数肯定没有返回值
// 一般将这样的函数称之为过程函数
def fun3() = {
"zhangsan"
}
def fun33() {
return "lisi"
}
println(fun33())
// TODO 如果调用函数的时候,不关心函数名称,只关心函数的执行逻辑的场合,那么def,函数名可以省略
// 将这样的函数称之为匿名函数
// def fun4() = {
// println("zhangsan")
// }
// TODO 如果不使用def来声明函数,那么就需要采用特殊的颜文字来声明
// 匿名函数由于没有名字,无法直接调用,需要将匿名函数赋值给变量来调用
val test = () => {
println("function zhangsan...")
}
// TODO 将匿名函数赋值给变量,那么这个变量的类型就是函数,所以可以调用。
//val name : String = "zhangsan"
test()
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
// TODO 1. 可以将这个对象赋值给其他变量来使用
// 变量就可以当作函数来使用
/*
class User {
}
User user = new User()
*/
// TODO 2. 可以将函数作为参数传递给函数
/*
User user = new User()
test(user)
public void test(User user) {
}
*/
// TODO 3. 可以将函数作为返回值在函数中返回。
/*
public User test() {
User user = new User();
return user;
}
*/
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
// TODO 1. 可以将这个对象赋值给其他变量来使用
// 变量就可以当作函数来使用
def test(): Unit = {
println("test...")
}
def test1( i : Int ): String = {
i.toString
}
def test2( i : Int, j: Int ): String = {
i.toString
}
def test3( i : Int, j: String ): Int = {
i
}
// 将函数赋值给变量,那么这个变量就是一个函数。就可以被调用
// 如果函数的参数列表的个数只有一个或没有,那么调用时可以省略小括号
// TODO 在下面的代码中,编译器会认为需要执行test函数,然后将函数的返回结果赋值给变量t
// 由于test函数的返回值为Unit,所以变量t赋值为Unit,不是方法,所以不能调用
//val t = test
//val t = test()
// TODO 如果想要将函数作为一个整体的对象赋值给变量,需要使用下划线的方式
// 当使用下划线时,编译器不会执行函数本身,而是将函数作为整体赋值给变量
// 变量就会变成函数类型,那么就可以被调用
// 这里的函数类型为 :() => Unit
// val f = test _
//val f1 = test1 _ // (Int) => String
// val f2 = test2 _ // (Int, Int) => String
//val f3 = test3 _ // (Int, String) => Int
// 函数调用
//f()
//println(f3(10, "zhangsan"))
// TODO 如果不使用下划线,也希望将函数作为整体赋值给变量
// 之前不加下划线之所以会执行函数,因为需要执行函数后才能推断出变量的类型,所以需要执行
// 如果不想要执行函数,那么就必须明确变量的类型,不能省略,也不能使用自动推断。
// 如果变量明确使用类型声明,那么赋值的函数需要匹配类型。
//val f = test _
val f11 : (Int) => String = test1
val f22 : (Int, Int) => String = test2
val f33 : (Int, String) => Int = test3
println(f11(20))
println(f22(20, 40))
println(f33(20, "lisi"))
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
// TODO 2. 可以将函数作为参数传递给函数
def test( name : String ): Unit = {
println("name = " + name)
}
def test1( name : Int ): Unit = {
println("name = " + name)
}
test("zhangsan")
test1(20)
// TODO 如果将函数作为参数传递, 那么参数名其实就是函数名
// 那么参数类型其实不就是函数类型
def test2( f : (Int)=>Int ): Unit = {
//println("name = " + name)
// 如果参数是函数类型,
// 那么可以通过函数调用的方式来使用这个参数
println(f(20))
}
def fun(i:Int): Int = {
i * 2
}
//val f = fun _
//test2( f )
//test2( fun _ )
test2( fun )
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
/*
public void test( String name ) {
name.substring()
}
String password = "123123"
test("password)
*/
def test( f: (Int, Int) => Int ): Int = {
f ( 10,20 )
}
// def fun(i : Int, j : Int): Int = {
// i + j
// }
// TODO 将函数作为参数传递给另外一个函数使用
// 一般情况下,不会独立声明这个函数,而是使用匿名函数
// 匿名函数 :(i : Int, j : Int) => { 函数体 }
//val result = test(fun)
//val result = test((i : Int, j : Int) => { i + j })
// TODO 匿名函数也可以遵循至简原则
// val result = test((i : Int, j : Int) => { i + j })
// TODO 如果函数逻辑代码只有一行,大括号可以省略
// val result = test((i : Int, j : Int) => i + j )
// TODO 如果参数类型可以推断,那么参数类型可以省略
// val result = test((i, j) => i + j )
// TODO 如果参数在逻辑中值使用了一次,那么参数可以使用下划线代替,参数就可以省略
// 下划线是按照参数的声明顺序进行代替的,第一个下划线就是代替第一个参数
val result = test(_ + _)
println(result)
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
def test( f : (String)=>Unit ): Unit = {
f( "zhangsan" )
}
// def fun( s : String ): Unit = {
// println("name = " + s)
// }
//test( ( s : String ) => { println(s) } )
//test( ( s : String ) => println(s) )
//test( ( s ) => println(s) )
// TODO 如果参数列表只有一个参数,那么可以省略小括号
//test( s => println(s) )
//test( println(_) )
test( println )
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
// TODO 3. 可以将函数作为返回值在函数中返回。
def fun(): Unit = {
println("fun...")
}
// TODO 函数会将满足条件的最后一行逻辑代码作为返回值
// 可以将一个函数作为返回值返回
def test() = {
fun _
}
// 调用函数
//val f = test()
//f()
test()()
}
def main(args: Array[String]): Unit = {
// TODO Scala 函数式编程 - 地狱难度
// TODO 函数是Scala中最重要的内容, 可以将函数看作对象来使用
// TODO 3. 可以将函数作为返回值在函数中返回。
// 一般将函数作为返回值返回时,使用的是嵌套函数
// def outer() : ()=> Unit = {
// def inner(): Unit = {
// println("inner function...")
// }
//
// inner
// }
//
// outer()()
// def sum( i:Int ) = {
// def innerSum(j : Int): Int = {
// i + j
// }
//
// innerSum _
// }
//
// println(sum(10)(20))
// operator(10)(20)(xxxx) => 30,200, -10
def operator( x : Int ) = {
def inner( y : Int ) = {
def oper( f : (Int, Int) => Int ): Int = {
f(x, y)
}
oper _
}
inner _
}
//operator(10)(20)((x,y)=>{x + y})