第1章 基础
- 调用函数和方法
- 调用函数,以math包中的函数调用为例
import scala.math._ "_"相当于java中的*
pow(2, 4) 返回16.0。如果是scala开头的包,可以省略scala - 方法,scala中没有静态方法
与之对应的是每一个类都有一个同名的伴生对象,定义在伴生对象中的方法可以直接调用
类的构造方法可以使用伴生对象中的apply方法
例如Array(1,2,3,4),其实调用的是Array.apply(1,2,3,4) 。
第2章 控制结构和函数
-
条件表达式
val b:Any = if (condition) 1 else "abc"
如果是if(condition) 1 <=> if (condition) 1 else () 返回类型是AnyVal
Unit用"()"表示。AnyVal继承Any -
语句的终止,可以使用Breaks,最好是使用while循环,通过标志位来终止循环
-
高级for循环和for推导式
for循环中可以放多个生成式,每个生成式可以带一个守卫。
例子: for(i<- 0 to 3 if i%2!=0; j<- 1 to 10 if j !=4)
for循环中定义任意多的变量在循环中使用
例子:for(i<- 0 to 3; from = 4 - i; j <- from to 10)
for推导式
例子: val cc=for(i<- 0 to 3) yield i*2 返回cc:Seq[Int]=Vector(0, 2, 4, 6)
cc的类型和for中的第一生成式有关 -
函数
函数定义,必须有=号。除非是递归调用的方式,不然不用声明返回值的类型
def sum(a:Int,b:Int) = {
a + b
}
+方式是Int隐式转换成RichInt之后的方法 -
可变参数
可变参数
def sum(args: Int) = {
//方法体里面使用的时候args变成了Seq
//如果是递归调用,直接将args传进去则会失败
sum(args.tail: _)//将Seq转成可变参数传入
//tail的意思是除第一个元素后的序列
} -
过程
不带=号,没有返回值,那就是过程
def process(i: Int){
//这就是一个过程
} -
懒值,在使用的时候才进行初始化
lazy val b=//操作开销比较大的资源 -
异常捕获
try{
//
}catch{
case e1:NPE => {}
case _ => {}
}
//通过模式匹配的方式来捕获不同的异常
第3章 数组相关操作
-
定长数组
Array("a","b")相当于java中的String[]
ArrayString 长度为10的定长数组
访问元素arr(0) -
变长数组:数组缓冲
ArrayBuffer("10","9")
val s = ArrayBufferString
数组尾端添加或者删除值都可以,且是一个高效的操作
s += "abc"
s ++= Array("g", "h")
s.trimEnd(5) 尾端移除5个元素
Array转ArrayBuffer和ArrayBuffer转Array
s.toArray.toBuffer -
遍历数组和缓冲数组
for(elem <- elems)
for (i <- 0 until elems.length) 遍历数组的索引
for(i <- 0 until (elems.length,2)) 调着遍历索引
for(i <- (0 until elems.length).reverse) 倒着遍历索引 -
练习,移除数组中第一个负数后面的所有负数
代码逻辑:
def main(args: Array[String]): Unit = {
//移除数组中第一个负数之后的所有负数
val ints = ArrayBuffer(1, -1, 1, 2, -3, 3, -2, -5, 0)
var first = true
//获取到所有的索引
val indexes = for (i <- 0 until ints.length if first || ints(i) >= 0) yield {
if (ints(i) < 0) first = false;i
}
//将满足条件的元素放到数组的前端,因为indexes(j)的值大于等于j,所以往前移的过程中,后面的值不会被覆盖
for (j <- 0 until indexes.length) ints(j) = ints(indexes(j))
ints.trimEnd(ints.length-indexes.length)
println(ints)
} -
创建多维数组
//创建规则的多维数组,3行4列的二维数组
val doubleArray = Array.ofDimInt
//创建不规则的多维数组,10行,每行数组的长度不确定的二维数组
val arr = new ArrayArray[Int]
for (i <- arr.indices) {
arr(i) = ArrayInt
}
//i是形参,在for的代码块中是不允许变更的。下面这种方式是错误的
for (elem <- arr) {
elem = new ArrayInt
}//编译失败的代码
//因为没有apply方法适用,所以用new的方式创建 -
scala和java的互转
//集合的隐式转换,如果调用java的api需要传List
import scala.collection.JavaConversions.bufferAsJavaList
val list=ArrayBuffer(1,2,3)
list.add(5)//适用java集合的方法添加元素
//java List转scala的Buffer
import scala.collection.JavaConversions.asScalaBuffer
val list1 = new util.ArrayListString
list1 += "a"
println(list1)
第4章 映射和元组
-
映射的创建,可以创建hash映射和树映射
创建不可变的映射
Map("a"->1, "b"->2)
创建可变的映射
scala.collection.mutable.Map("a" -> 1, "b" -> 2)
创建一个空的可变映射,需要指定映射的方式
scala.collection.mutable.HashMapString,Int -
获取映射中的值
map("a")直接获取的方式可能会报错
Exception in thread "main" java.util.NoSuchElementException: key not found: c
正确的调用方式,get()调用返回Option进行模式匹配Some或者None 或者getOrElse("a",3)给默认值 -
更新映射中的值
为可变map添加值
mm += ("b" -> 3) //如果key已经存在,则修改
mm -= "c" //移除对应的key
mm ++= Map("d" -> 4)
mm --=Seq("d","a") -
迭代映射
for ((k,v) <- mm)
反转映射
val newmm=for((k,v)<- mm if k!="a") yield (v,k) -
排序映射
scala默认的是Hash映射,如果想要使用树结构的映射,需要key有序。scala只有一种不可变的Map
val sortMap = scala.collection.immutable.SortedMapInt,String还有一种方式,就是使用java的TreeMap来实现有序的映射。 如果按照插入的顺序访问映射,使用scala.collection.mutable.LinkedHashMap
-
与java的互转
import scala.collection.JavaConversions.mapAsScalaMap
import scala.collection.JavaConversions.mapAsJavaMap -
使用模式匹配获取元组的值
//模式匹配的方式获取元组的值
val t = (1, 2, "a", "b")
val (f, second, _, _) = t
_只是一个占位符,不使用 -
拉链操作
Array("a","b").zip(Array(1,2)).toMap
第5章 类
-
简单的类和无参方法
//scala不使用这种定义方式
class Counter{
private var i =0
def increment(): Unit ={
i+=1
}
def current=i
}//改变状态的方法Increment //获取值的方法,去掉了() class Counter{ var age=0 } 编译的时候自动创建setter和getter方法 getter方法是age(),counter.age调用,省略了() setter方法是age_=(参数),counter.age_=(1)调用,也可以重新setter方法 class Counter{ private var privateAge:Int=0 def age=privateAge def age_=(): Unit ={ //set逻辑 } } 和java一样定义setter和getter方法
如果把属性声明成private,则scala编译成java程序的时候setter和getter方法都声明成private的
如果属性声明成val,只有getter方法生成
如果不想要setter方法和getter方法,属性声明成private[this] -
私有字段的访问
private修饰符
class Counter{
private var privateAge:Int=0
def age=privateAge
def age_=(): Unit ={
//set逻辑
}
}类中能访问对象的私有属性包括非this对象的私有属性 class Counter{ private var privateAge:Int=0 def age=privateAge def age_=(): Unit ={ //set逻辑 } def compare(other:Counterr){ other.privateAge也是能访问的 } } 如果只想当前对象能访问私有属性,则使用private[this]来进行修饰 如果private[otherCounnter]修饰Counter的私有属性,如果指定其他类的类名,那么其他类中也可以访问Counter对象的私有属性
-
scala类编程javaBean
@BeanProperty
var name:String=_
为属性增加注解,自动生成setName方法和get方法,变量不能声明成private
总共生成4个方法
name
name_=(name:String)
setName(name:String)
get() -
辅助构造器
class Counter(address:String){
private var privateAge:Int=0
privateAge = 1
@BeanProperty
var name:String=_
def this(name:String,address:String){
this(address)
this.name=name
}
def this(name:String,other:String,address:String){
this(name,address)
this.name+=other
}
}辅助构造器必须调用主构造器,第二个辅助构造器其实也是调用了主构造器 class Counter(val address:String,private var tt:String) 主构造器中可以使用修饰符val、var、private,如果不声明,默认是val 加了修饰符,参数会被声明成属性。 如果没有修饰符,方法中使用了参数,也会被声称属性。如果没有使用,只是访问,不会被声明成字段 禁止调用主构造器 class Counter private(address:String) 这样只能调用辅助构造器了嵌套类
-
嵌套类
嵌套类,类中可以嵌套类,函数中可以嵌套函数,对象中可以嵌套类
第6章 对象
-
单例对象,定义一个object就是一个单例对象,对象在首次使用的时候构造出来
-
伴生对象,伴生对象和伴生类可以互相访问私有属性,前提是声明在同一个源文件中
类访问伴生对象中的私有方法的时候,必须类名.方法名的方式调用,不能直接方法名调用,因为方法不在同一个域中 -
扩展类或特质的对象
abstract class AbstractNothing(des:String){
def a()
def b()
}object ImplNothing extends AbstractNothing("nothing") { override def a(): Unit = {println("aaa")} override def b(): Unit = { println("bbb") } } class Counter(address:String){ private var privateAge:Int=0 @BeanProperty var name:String=_ def this(name:String,address:String){ this(address) this.name=name } def this(name:String,other:String,address:String){ this(name,address) this.name+=other } } object ImplNothing2 extends Counter("address") { //只能访问到非private的属性和方法 ImplNothing2.name ImplNothing2.setName("a") }
-
枚举对象
//枚举对象
object EnumColor extends Enumeration {
// val GREEN, RED, BLUE = Value
//调用value方法返回一个Value的实例
val GREEN=Value(0,"abc")
val RED=Value(1,"abc")
val BLUE=Value(2,"abc")
//为枚举实例定义id和name,如果没有定义id就是前面一个的id+1,如果前面没有那就从0开始
//name没有定义那就是GREEN作为name
}
object TestH{
def main(args: Array[String]): Unit = {
val blue: EnumColor.Value = EnumColor.BLUE
}
}
第7章 包和引入
第8章 继承
-
类型检查和转换
if (blue.isInstanceOf[EnumColor.Value]) {
val newBlue=blue.asInstanceOf[EnumColor.Value]
}//如果要准确判断是不是一个类的对象 if (blue.getClass == classOf[Counter]) { } 最优的方法是使用模式匹配,优于类型检查和转换 blue match { case a: Counter => { } case _ => { } }
-
典型构造顺序和提前定义的问题
object Demo02 {
def main(args: Array[String]): Unit = {
val et = new Class2()
val arr = et.env
println(arr.length) //打印的结果是0
}} class Class1{ val arraySize=10 val env:Array[String]=new Array[String](arraySize) } class Class2 extends Class1{ override val arraySize=2 } 解释,先调用父类的构造方法,父类初始化arraySize,此时创建env,想要获取arraySize,调用方法arraySize(),但是这个方法已经被重写(重写了字段,就是重写了getter方法),这是调用子类的方法arraySize(),返回子类的arraySize,此时子类的arraySize还没有初始化成2。所有的int值,在分配 空间的时候都会被初始化成0,所以得到的数组长度为0 采用提前定义的方式来解决这个问题 先初始化子类中的某些字段 class Class2 extends { override val arraySize = 2 } with Class1{ }
-
scala继承层级
与java中基本类型对应的类和Unit类都是继承AnyVal
其他类都是继承AnyRef,相当于java中的Object
AnyRef和AnyVal都是继承自Any
第9章 文件和正则表达式
- 后面补充
第10章 特质
- 后面补充
文章来源: 博客园
- 还没有人评论,欢迎说说您的想法!