Scala
package chapter01
object Hello {
//scala源码中包含了main方法,在编译后自动形成了public static void main
//Scala在编译源码时,会生成两个字节码文件,静态main方法执行另外一个字节码文件中的成员main方法
//scala是完全面向对象的语言,没有静态的方法,只能通过模拟生成静态方法
//编译时将当前类生成一个特殊的类==》Scala01_HelloWord$,然后创建对象来调用这个对象的main方法
//一般情况下,将加$的类的对象,称之为“半生对象”
//伴生对象中的内容,都可以通过类名访问,来模拟Java中的静态语法
//伴生对象语法规则:使用object声明
//scala中没有public关键字,默认所有的访问权限都是公共的。
//scala中没有void关键字,采用特殊的对象模拟:Unit
//scala中声明方法采用关键字def
//方法后面的小括号是方法的参数列表
//scala中的参数列表的声明方式和Java不一样
//java:String 参数名
//scala: 参数名 :类型
//java 中方法的声明和方法直接连接
//scala中将方法的返回值类型放置在方法声明的后面使用冒号连接
def main(args: Array[String]): Unit = {
println("Hello Word")
}
}
package chapter01
object Scala02_StringPrint {
def main(args: Array[String]): Unit = {
//打印字符串
println("打印字符串")
//变量
val name = "ApacheCN"
val age = 1
val url = "www.atguigu.com"
print("name=" + name + "age=" + age + "url=" + url + "\n")
printf("name=%s,age=%d,url=%s\n", name, age, url)
//插值字符串
println(s"name=${name},age=${age},url=${url}")
//格式化
print(f"name=${name},age=${age}%.2f,url=${url}\n")
//原值
println(raw"name=${name},age=${age}%.2f,url=${url}\n")
//多行字符串
val s=
"""
|jfasjdflasjf
|fsaldjfsklafj
|fasfjas
|fdklgjdsfgj
|""".stripMargin
print(s)
}
}
变量的声明
object Scala01_Var {
def main(args: Array[String]): Unit = {
var name: String = "张三"
//声明变量
//var 变量名称:变量类型=变量的值
//使用var声明的变量的值是可以修改的
//scala声明变量必须显示的初始化
//错误
/*
var name:String
name="张三"
*/
var age: Int = 10
var c: Char = 'c'
var d: Double = 12
var b: Boolean = true
age = 20
name = "李四"
//使用val声明的变量的值不可以修改
//在方法的外部声明的变量如果采用val关键字,等同于使用final修饰
val name1: String = "Zhangsan"
//name1="lisi" 错误
}
}
object VarValDemo1 {
def main(args: Array[String]): Unit = {
var a:Int=10;
a=20
print(a)
val b:Int=100
print(b)
var c =10//scala的类型推导
//a=1l 报错
/*
注意:在Scala中,能用常量的地方不要用变量
2、在声明的同时给变量和常量赋值
3、
*/
}
}
变量命名规则
package chapter02
object NameRegular {
//命名规则
def main(args: Array[String]): Unit = {
val ++ = 10
print(++)
//val a++ =10
val a_++ =10
val ` ` =30//空格作为变量名
val `type` =2
}
}
/*
标识符(常量,变量,对象,方法,函数)命名规范:
1、使用Java的命名规则
Scala中的下划线要慎用
2、不用使用$
将来Scala编译的时候,一些类会自动添加$
3、支持使用运算符(+-/*...)来命名标识符
在Scala中没有真正的运算符,所有的运算符其实都是对象的方法
a:不要使用单个运算符作为变量名和常量
b:字符和运算符不能混用
a++不允许
c:如果混用,可以用_隔开
4、可以使用``定义任意字符,主要为了兼容Java中的一些标识符名
*/
数据输入
package chapter02
import java.io.{BufferedReader, InputStreamReader}
import java.util.Scanner
import scala.io.StdIn
object Input {
def main(args: Array[String]): Unit = {
//java的写法
//1、高级写法
val scan:Scanner= new Scanner(System.in)
println(scan.nextLine())
//2、把标准输入流转换成字符流(低级写法)
val reader :BufferedReader=new BufferedReader(new InputStreamReader(System.in,"utf-8"))
val line:String =reader.readLine()
println(line)
//Scala的写法
val line1=StdIn.readLine()
println(line1)
val line2=StdIn.readLine("请输入:")//"请输入“会被先打印出后输入
println(line2)
}
}
数据转换
package chapter02
object Type {
def main(args: Array[String]): Unit = {
val a:Long=1
val b:Double=2
val c:Double=a
val d=b.toInt
val s="123"
val i=Integer.parseInt(s)
val i1=s.toInt
println()
}
}
/*
Byte
Short
Long
Int
Float
自动转换(提升):
byte->short->float->double
char->int
强制转换类:
java:(int)1L
scala:
.toInt
*/
运算符
package chapter02
object Operator1 {
def main(args: Array[String]): Unit = {
val r:Int=1.+(2)
println(r)
println(1+3)
val s=10
var i=1
i+=1
println(i)
val a="a"
val b=a+"b"
val c=a+"b"
println(b==c)//true
println(b.equals(c))//true
println(b.eq(c))//false
}
}
/*
运算符
在Scala中,没有真正的运算符,所谓运算符,其实是一个方法(函数)名!
+-/都是方法名
1、在Scala中,调用方法的点,可以省略
2、在给方法传递参数的时候,如果这个方法的参数只有一个参数或者没有参数,则括号也可以省略
++ --这两个垃圾运算符被去掉
scala:
==等价于equals
equals等价于==
自定义类型应该重写equals
eq 等价于Java中的==
*/
数据类型 | 描述 |
---|---|
Unit | 表示无值,和其他语言中void等同。用作不返回任何结果的方法的结果类型。Unit只有一个实例值,写成()。 |
Null | null , Null 类型只有一个实例值null |
Nothing | Nothing类型在Scala的类层级的最低端;它是任何其他类型的子类型。 当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数或者变量(兼容性) |
package chapter02
import scala.io.StdIn
object IfDemo {
def main(args: Array[String]): Unit = {
val m=10
val n=20
val max=if(m>n)m else n
println(max)
val i=if(m>n){
100
}else 1
println(i)
var d=10
d=30
println(d=40)//()
val q=90
val s:Double=Math.pow(q,2)
println(s)
}
}
/*
重要:
在Scala中,任意的语法结构(执行的语句,表达式等等)都有值!
是执行的最后一样代码的值自动返回
注意:
1、在Scala中,赋值的语句的值是Unit
*/
/*
流程控制
1、顺序流程
2、分支
if
和Java中的完全一致
模式匹配
替换掉Java中的switch,语法有点像,但是远远超过Java的switch
3、循环
*/
for循环
object For1 {
def main(args: Array[String]): Unit = {
val a:String="abc"//字符串
//遍历容器 c只读,不能改
for(c <-a){
println(c)
}
//使用for输出1-100
for(i <- 1.to(100)){
print(i+" ")
}
println()
//使用for输出1-100的所有奇数
for(i <- 1 to(100,2)){//to有两个参数,参数1就是结束的值,参数2是布长;
print(i+" ")
}
println()
for(i <- 1 to 100 by 2){
print(i +" ")//效果同上
}
println()
//使用for输出 100-1
for(i <-1 to 100 reverse){
print(i+" ")
}
println()
}
}
/*
Scala中的for循环,本质是一种遍历,遍历集合(容器)中的每个元素,
当遍历完最后一个元素之后,自动终止
1、如果要使用for,必须先有容器
2、
*/
object For2 {
def main(args: Array[String]): Unit = {
//输出1-100的奇数
for (i <- 1 to 100 if (i % 2 == 1)) {
print(i + " ")
}
println()
//
for (i<- 0 until 100){//[0,100)
print(i+" ")
}
println()
//引入其它变量
for (i <- 1 to 100 if(i % 2==0);j=i*i if(j<1000);k=j*j){
println(s"i=$i,j=$j,k=$k")
}
}
}
终止for循环
package chapter03
import scala.io.StdIn
import scala.util.control.Breaks._
object For3 {
def main(args: Array[String]): Unit = {
val n = StdIn.readInt()
var isPrime = true
/* try {
for (i <- 2 until n) {
if (n % i == 0) {
isPrime = false
throw new IllegalArgumentException
}
}
} catch {
case _ =>
}*/
//或
//结束循环:本质是自己抛异常,再去捕捉异常
//while ,do while ,for 都可以使用
breakable {
for (i <- 2 until n) {
if (n % 2 == 0) {
isPrime = false
break()
}
}
}
if (isPrime) {
println(s"$n 是一个质数")
} else {
println(s"$n 不是一个质数")
}
}
}
/*
Scala中没有break关键字
*/
for嵌套循环
package chapter03
object For4 {
def main(args: Array[String]): Unit = {
//9*9乘法表
for (i <- 1 to 9) {
for (j <- 1 to i) {
print(s"$j*$i=${i * j}\t")
}
println()
}
println()
for (i <- 1 to 9; j <- 1 to i) {//所有的代码都在内循环,则可以使用的嵌套
//实际使用很少
print(s"$j*$i=${i * j}\t")
if (i == j) println()
}
}
}
函数至简原则:能省则省
1至简原则细节
(1)return可以省略,Scala会使用函数体的最后一行代码作为返回值
(2)返回值类型如果能够推断出来,那么可以省略
(3)如果函数体只有一行代码,可以省略花括号
(4)如果函数无参,则可以省略小括号。若定义函数时省略小括号,则调用该函数时,也需省略小括 号;若定时函数时未省略,则调用时,可省可不省。
(5)如果函数明确声明Unit,那么即使函数体中使用return关键字也不起作用
(6)Scala如果想要自动推断无返回值,可以省略等号
(7)如果不关心名称,只关系逻辑处理,那么函数名(def)可以省略
(8)如果函数明确使用return关键字,那么函数返回就不能使用自行推断了,需要声明返回值类型
高阶函数
package chapter04
object Function_1 {
//函数:入参(方法参数),出参(返回值)
def main(args: Array[String]): Unit = {
println(add(1,2,4))
println(add(1,c=2))//按照参数名传递参数
println(add(c=10,a=1,b=32))//按照参数名传递参数
println(test())
foo(f)
def add(a:Int ,b:Int=3,c:Int)=a+b+c
def test() = "Test"
def f()={
println("a")
}
def foo(x:() => Unit)={
println(x)
x()
}
}
/*
1、函数可以定义在任何位置
可以在函数内定义函数
2、可以把函数当成一个值返回给函数的调用者,
函数的调用者就可以在函数的外部去调用这个返回的函数
3、可以把函数当作一个值,传递给另外一个函数
4、如果一个函数可以返回一个函数作为返回值,或者可以接收一个(多个)函数作为参数
那么这个函数就称为高阶函数
*/
}
匿名函数
package chapter04
object Function_2 {
def main(args: Array[String]): Unit = {
val a=()=>println("aaa")
// foo( ()=>{println("匿名函数")} )
foo((a:Int,b:Int)=>a+b)//或foo((a,b)=>a+b)
foo(_+_)//第一个下划线表示第一个参数,类推
}
def foo(add:(Int,Int)=>Int)={
println(add(10, 20))
}
/*
def foo(f:()=>Unit)={
f()
}
*/
}
/*
匿名函数:
没有名字的函数,就是匿名函数
用处:
1、作为实参,直接传递给高阶函数
2、直接作为高级函数的返回值
2、传递:
foo((a:Int,b:Int)=>a+b)
3、在传递匿名函数的时候,参数的类型一般可以利用上下文,让Scala自动去推导
4、foo(_+_)
要求:1、匿名只能有两个函数
2、每个参数只使用一次
3、第一个_表示第一个参数,第二个下划线表示第二个参数
*/
package chapter04
object Function_4 {
def main(args: Array[String]): Unit = {
//遍历
val arr = Array(30, 50, 73, 60, 11, 20)
foreach(arr, a => println(a))
//使用给定的条件,对数组过滤
val arr2=filter(arr,x=>x%2==0)
foreach(arr2,println)
val arr3=map(arr,x=>x*x)
foreach(arr3,println)
println(reduce(arr, (x:Int, y:Int) => {
println(s"x=$x,y=$y")
x + y
}))
}
def map(arr:Array[Int],op:Int => Int)={
for (elem <- arr) yield op(elem)
}
def foreach(arr: Array[Int], op: Int => Unit) = {
for(elem<- arr){
op(elem)
}
}
def filter(arr:Array[Int],condition:Int=>Boolean)={
for(elem <- arr;if condition(elem))yield elem
}
def reduce(arr:Array[Int],op:(Int,Int)=>Int):Int={
var sum=0;
for (elem <- arr) {
sum=op(sum,elem)
}
sum
}
}
/*
经典的高阶函数
foreach
遍历集合中的每个元素
filter
过滤,过滤条件可以通过一个返回boolean的函数来体现
map
映射,一进一出
reduce
聚合操作
1 to 100
*/
闭包
package chapter04
object Closure {
def main(args: Array[String]): Unit = {
def f:Int=>Int=foo()//!
val r:Int=f(10)//能够访问到a,是因为闭包的存在
println(r)
def f1=foo1()
println(f1())
println(f1())
val f2=foo1()
println(f2())
}
def foo():Int=>Int={
var a=10
(b:Int)=>a+b
}
def foo1()={
var a=10
()=>{a+=1;a}
}
}
/*
闭包:
一个函数,如果访问了外部的局部变量,则这个函数和它访问的局部变量,称为一个闭包
闭包会阻止外部局部变量的销毁,可以把局部变量的使用延伸到函数的外部
*/
面向对象
package chapter05
import scala.annotation.meta.beanGetter
import scala.beans.BeanProperty
object ObjectDemo_1 {
def main(args: Array[String]): Unit = {
val user = new User()
println(user)
println(user.age)
user.eat()
user.age_$eq(100) // <=> user.age=100
println(user.age)
user.name_("haha")
user.setAge(32)
println(user)
}
}
class User {
//定义属性
@BeanProperty var age = 10
private var name="xugao"
val country = "china"
private var a1 = 100
//类定义方法
def eat(): Unit = {
println("eat" + this.name)
}
def name_(name:String): Unit ={
this.name=name
}
override def toString = s"User($age, $name, $country)"
//自己写的
/* def getAge(){
age
}
def setAge(age: Int): Unit = {
this.age = age
}*/
}
/*
Scala默认的getter和setter不满足JavaBean规范
getAge() setAge(...)
需要注解,Scala会自动生成get、set
*/
构造器
package chapter05
import scala.beans.BeanProperty
object Obj_3{
def main(args: Array[String]): Unit = {
val person=new User2(10,"xu","男")
val user=new User2()
println(user.age)
//给类取别名
type U=User2
val u=new U()
println(u.age)
println(u.getClass.getName)//获得类名
}
}
class User2(@BeanProperty var age:Int, var name:String, var sex:String){
//辅助构造器
def this(){
//首行必须调用主构造器
this(10,"abc","male")//构造器内调用构造器
}
def this(c:Int){
this()//调用前面的构造器
}
var a=10
def eat ={
println(sex)
this.age
}
}
/*
1、调用构造器创建对象,可以给属性赋值
2、在类名的后面添加需要的一些属性,这些在创建对象的时候,可以给这些属性赋值
3、类名后面跟的其实就是构造器,这个就是主构造器,一个类唯一一个
4、def this()
首行必须是调用主构造器
辅助构造器的参数,仅仅是一个只能在当前的这个辅助构造器内使用的普普通的一个常量
5、后面的辅助构造器可以调用前面的,前面的不能调用后面的
*/
包的导入
package chapter06
//import java.util._ //导入util下的所有类
//import java.util.HashMap
//import java.util.TreeMap
//import java.util.{TreeMap,HashMap} 导入TreeMap和HashMap
//导包的时候给类取别名
import java.util.{HashMap=>HM}
//不用HashMap,但用util下的其他类
import java.util.{TreeMap=>_,_}
私有化构造器
package chapter06
object Modifier_1 {
def main(args: Array[String]): Unit = {
val user=new User(1)
println(user.a)
}
}
//构造器私有
class User private[chapter06](var age:Int){//该构造器只能在chapter06下调用
private [chapter06] val a:Int=10
private val b:Int=2
}
继承
package chapter06
import java.awt.im.InputMethodRequests
object Extends_1 {
def main(args: Array[String]): Unit = {
new B(1).foo()
}
}
class A(val a:Int){
def this(){
this(2)
}
println("A 主构造器")
def foo()={
println("A foo")
}
}
class B(val b:Int) extends A{//可以调用辅助构造器
println("B 主构造器")
override def foo()={
super.foo()
println("B foo")
}
}
/*
1、scala 是单继承
2、Scala没有接口,但是提供了更加强的trail(特质)
注意:
1、复写方法,必须添加关键字 override
2、构造器的特征
先执行父类的构造器,然后才是子类的构造器
父的主构造器->子类的主构造器->...->子类构造器
属性的复写
1、val 只能复写 val 和不带参数的def
2、var 只能复写抽象的 var
*/
属性覆写
package chapter06
object Extends_2 {
def main(args: Array[String]): Unit = {
val b=new B
println(b.a)
}
}
class A{
var a:Int=10
}
class B extends A {
override val a:Int=20
}
抽象类
package chapter06
object Abs1 {
def main(args: Array[String]): Unit = {
val a:A=new B
a.foo()
}
abstract class A(var a:Int){
//属性只声明,不初始化,这就是抽象字段
var b:Int
//方法只有声明,没有实现,就是抽象方法
def foo():Int
}
class B() extends A(2){
override var b: Int = _
override def foo(): Int ={
println("hello")
1
}
}
/*
scala的抽象类可以有哪些成员:
1、普通类可以有的,抽象类都可以
2、抽象类可以有抽象方法和抽象字段(属性)
3、抽象类不能够创建对象
*/
}
匿名内部类
伴生类、伴生对象
package chapter06
object Abs2 {
def main(args: Array[String]): Unit = {
//创建一个匿名内部类的对象
val a=new C(20) {
override var b: Int = 2
override def foo(): Int = 4
}
println(a.b)
}
}
abstract class C(var a:Int){
var b:Int
def foo():Int
}
单例设计
package chapter06
object Single1 {
def main(args: Array[String]): Unit = {
D.foo
D()//等价于D.apply()
}
}
object D{
def foo=println("foo...")
def apply():Int={
println("apply")
10
}
}
class D{
}
/*
scala中单例
使用object关键字,声明出来的对象就是一个单例对象
独立对象
任何的对象(object,也可以是new),只要提供了一个apply方法,都可以
像使用方法一样去调用对象
如果在同一个.scala文件中,一个object的名字和一个class的名字一样,则他们
分别叫伴生类和伴生对象
编译成字节码之后,伴生对象的是静态方法,伴生类是非静态(对象方法)
*/
trait
package chapter07
import java.util.logging.Logger
object Trait_1 {
def main(args: Array[String]): Unit = {
val usb: Usb = new HuaweiUsb
usb.insert
usb.work
usb.pop
}
}
class Logger{
println("logger 类的构造器")
def print()={
println("开始打印日志...")
}
}
trait Usb {
println("Usb 类的构造器 第一个混入的")
//抽象字段
val name: String
def insert: Unit
def work: Unit
def pop: Unit
def init() = {
println("usb 开始初始化...")
}
}
trait MyException {
println("MyException 的构造器 第二个混入")
def throwExec: Exception
}
class HuaweiUsb extends Logger with Usb with MyException {
override val name: String = "huawei"
override def insert: Unit = {
println("华为 usb开始插入...")
init()
}
override def work: Unit = {
println("华为 usb开始工作...")
print()
}
override def pop: Unit = {
println("华为 usb退出工作...")
}
override def throwExec: Exception = new RuntimeException("usb出现异常")
}
/*
scala:
scala没有提供接口,但是提供了更加强大的:trait特质
1、抽象类中有的东西,trait都可以有
抽象类是累,只能单继承
trait 可以多继承
2、当类继承类和trail,对前面用extends,后面的统一用with(混入)
*/
多混入问题
package chapter07
object Trait_2 {
def main(args: Array[String]): Unit = {
val abc =new ABC
abc.foo()
println("***************")
val my=new My with A with B//动态混入
my.foo()
}
}
class My{
}
class ABC extends A with B with C{
override def foo(): Unit = {
super.foo()
println("ABC...")
}
}
trait A{
def foo()={
println("A...")
}
}
trait B extends A{
override def foo()={
println("B...")
}
}
trait C extends A{
override def foo() ={
super[A].foo()//如果没有[A]则按混入顺序往前找,调用的是B中的foo方法
println("C...")
}
}
/*
1、如果一个类混入的特质中有相同的实现好的方法,则会产生成员冲突
2、可以使用菱形的继承结构解决冲突问题,冲突解决之后,方法是最后混入的那个
3、super[A] super具体指代
4、动态混入(叠加)
*/