类的定义
class Counter{
定义类的字段和方法
}
定义字段:使用关键字val
或者var
定义方法:def 方法名(参数列表):返回结果类型={方法体}
def increment(step: Int): Unit = {
value += step
}
def current(): Int = {
value
}
联系起来就是
var value = 0
def increment(step: Int): Unit = {
value += step
}
def current(): Int = {
value
}
类的使用:使用关键字new
创建一个类的实例
val myCounter = new Counter
myCounter.value = 5//字段赋值
myCounter.increment(3)//调用方法
println(myCounter.current)//调用无参方法时,可以将省略括号
scala
类的所有成员默认是公开的,即如何作用域都能直接访问到,为了数据的安全性,我们一般要设置他的可见性,在scala
中类的可见性分为以下几种:
- 默认的:如何作用域都可以访问
private
:只对本类型和嵌套类型可见protected
:本类型和其继承类型均可见
为了数据的安全性,我们需要和Java
一样,将字段设置为private
,然后定义两个方法来对数据进行读取和修改
原本的Counter
改成
package ObjectClass
class Counter {
private var privateValue = 0
var value = privateValue
def getPrivateValue(): Int = {
privateValue
}
def setPrivateValue(privateValue: Int): Unit = {
if (privateValue > 0) this.privateValue = privateValue
}
def increment(step: Int): Unit = {
value += step
}
def current(): Int = {
value
}
}
调用需要改成
val myCounter = new Counter
myCounter.setPrivateValue(5)
myCounter.increment(3)//调用方法
println(myCounter.current)//调用无参方法时,可以将省略括号
定义方法:def 方法名(参数列表):返回结果类型={方法体}
构造器Scala
类的定义主体就是类的构造器,称为主构造器。在类名之后用圆括号列出主构造器的参数列表=
主构造器的参数可以使用var
和·val
关键字,scala
内部将自动为这些参数创建私有字段,并且提供对应的访问方法
如果不需要类的参数成为类的字段,则不加关键字var
和val
即可
定义一个带参数的构造器
class Counter02(var name:String)
使用构造器,并且对其参数来进行处理
var myCounter02 = new Counter02("张三")
//调用读方法
println(myCounter02.name)
//调用写方法
myCounter02.name = "李四"
println(myCounter02.name)
Scala
类可以包含零个或多个辅助构造器。辅助构造器可以使用this
来进行定义,返回类型是Unit
每一个辅助构造器的第一个表达式必须是调用一个此前已经定义的辅助构造器或者主构造器,调用的形式:this(参数列表)
class Counter03 {
private var value = 0
private var name = ""
private var step = 1 //计算器的默认递进步长
println("the main constructor")
def this(name: String) { //第一个辅助构造器
this() //调用主构造器
this.name = name
printf("the first auxiliary constructor,name:%s\n", name)
}
def this(name: String, step: Int) { //第二个辅助构造器
this(name) //调用前一个辅助构造器
this.step = step
printf("the second auxiliary constructor,name:%s,step:%d\n", name, step)
}
def increment(step: Int): Unit = {
value += step
}
def current(): Int = {
value
}
}
调用
println(new Counter03)
println(new Counter03("Jack"))
println(new Counter03("Jack",20))
对象
Scala
采用单例对象来实现Java
静态成员同样的功能
使用Object
关键字定义单例对象
object Person {
private var lastId = 0
def newPersonId() = {
lastId += 1
lastId
}
}
使用示范
println(Person.newPersonId())
println(Person.newPersonId())
println(Person.newPersonId())
伴生对象的使用
class Person(val name: String) {
private val id = Person.newPersonId() //调用了伴生对象中的方法
def info() {
printf("The id of %s is %d.\n", name, id)
}
}
object Person {
private var lastId = 0 //一个人的身份编号
def newPersonId() = {
lastId += 1
lastId
}
def main(args: Array[String]) {
val person1 = new Person("Lilei")
val person2 = new Person("Hanmei")
person1.info()
person2.info()
}
}
Apply
方法
思考下行代码的执行过程
val myStr = Array("BigData","Spark")
实验使用
object ApplyTest {
def main(args: Array[String]): Unit = {
val myApplyTest = new ApplyTest
myApplyTest("xxx")
myApplyTest.apply("aaa")
}
}
class ApplyTest {
def apply(Parm: String): Unit = {
println("apply method called:" + Parm)
}
}
伴生对象中的apply
方法:将所有类的构造方法以apply
方法的形式定义在伴生对象中,这样伴生对象就像生成类实例的工厂,而这些apply
方法也被称为工厂方法
class Car(name: String) {
def info(): Unit = {
println("Car name is " + name)
}
}
object Car {
def apply(name: String) = new Car(name)
}
object CarTest {
def main(args: Array[String]): Unit = {
val myCar = Car("BYD")
myCar.info
}
}
为什么要设计apply
方法
- 保持对象和函数之间使用的一致性
- 面向对象:‘对象.方法’ VS 数学:'函数(参数)'
Scala
中一切都是对象,包括函数也是对象
update
方法
//声明有一个长度为3的字符串数组,每个数组元素初始化为null
val myStr = new Array[String](3)
myStr(0) = "BigData"//实际上时执行了Array.update(0,"BigDate")
myStr(1) = "Hadoop"
unapply
unapply
方法用于对对象进行解构操作,与apply
方法类似,该方法也会被自动调用- 可以认为
unapply方法是
apply方法的反向操作,apply
方法接受构造参数变成对象,而unapply
方法接受一个对象,从中提取值
object upApply {
def main (args: Array[String]) {
val Car02(carbrand,carprice) = Car02("BMW",800000)
println("brand: "+carbrand+" and carprice: "+carprice)
}
}
class Car02(val brand:String,val price:Int) {
def info() {
println("Car brand is "+ brand+" and price is "+price)
}
}
object Car02{
def apply(brand:String,price:Int)= {
println("Debug:calling apply ... ")
new Car02(brand,price)
}
def unapply(c:Car02):Option[(String,Int)]={
println("Debug:calling unapply ... ")
Some((c.brand,c.price))
}
}
继承
类的层次结构
抽象类
- 如果一个类中含有为实现的成员,则必须使用
abstract
关键字进行修饰,定义为抽象类
abstract class abstractTest {
val carBrand: String//字段没有初始化,就是一个抽象字段
def info()//抽象方法
def greeting(): Unit = {
println("hello")
}
}
扩展类Scala
中只支持单一继承,不支持多重继承。使用关键字extends
表示继承关系
object extendsTest {
def main(args: Array[String]): Unit = {
val man = new Man()
val woman = new Woman()
man.info()
man.info2()
woman.info()
woman.info2()
}
}
abstract class human {
val sex: String
def info()
def info2() {
println("你好,人类")
}
}
class Man extends human {
override val sex: String = "男"
override def info(): Unit = {
printf("这是一个%s人\n", sex)
}
override def info2(): Unit = {
println("你好,男人")
}
}
class Woman extends human {
override val sex: String = "女"
override def info(): Unit = {
printf("这是一个%s人\n", sex)
}
override def info2(): Unit = {
println("你好,女人")
}
}
option
类
跳转顶部
特质
使用关键字trait
定义特质
trait Flyable {
var maxFlyHeight: Int //抽象字段
def fly() //抽象方法
def breathe() { //具体的方法
println("I can breathe")
}
}
使用关键字extends
或者·with
将特质混入类中,如果特质中含有抽象成员,则必须实现,否则只能被定义为抽象类
class Bird(flyHeight:Int)extends Flyable{
override var maxFlyHeight: Int = flyHeight
override def fly(): Unit = {
println("i can fly at the height of %d",maxFlyHeight)
}
}
使用
val bird = new Bird(100)
bird.fly()
将多个特质到类中
trait Flyable {
var maxFlyHeight:Int //抽象字段
def fly() //抽象方法
def breathe(){ //具体的方法
println("I can breathe")
}
}
trait HasLegs {
val legs:Int //抽象字段
def move(){printf("I can walk with %d legs",legs)}
}
class Animal(val category:String){
def info(){println("This is a "+category)}
}
class Bird(flyHeight:Int) extends Animal("Bird") with Flyable with HasLegs{
var maxFlyHeight:Int = flyHeight //重载特质的抽象字段
val legs=2 //重载特质的抽象字段
def fly(){
printf("I can fly at the height of %d",maxFlyHeight)
}//重载特质的抽象方法
}
类的使用
val b = new Bird(108)
b.info()
b.fly()
b.move()
模式匹配
最常见的模式匹配是match
语句,match
语句用在当需要从多个分支中进行选择的场景
println("Please input the score:")
val grade=readChar()
grade match{
case 'A' => println("85-100")
case 'B' => println("70-84")
case 'C' => println("60-69")
case 'D' => println("<60")
case _ => println("error input!")
}
- 通配符
_
相当于Java
中的default
分支 match
结构中不需要break
语句来跳出判断,Scala
从前往后匹配到一个分支后,会自动跳出判断
除了匹配特定的常量,还能匹配某种类型的所有值
for (elem <- List(6, 9, 0.618, "Spark", "Hadoop", 'Hello)) {
val str = elem match {
case i: Int => i + " is an int value." //匹配整型的值,并赋值给i
case d: Double => d + " is a double value." //匹配浮点型的值
case "Spark" => "Spark is found." //匹配特定的字符串
case s: String => s + " is a string value." //匹配其它字符串
case _ => "unexpected value:" + elem //与以上都不匹配
}
println(str)
}
可以在match
表达式的case
中使用守卫式(guard
)添加一些过滤逻辑
for (elem <- List(1, 2, 3, 4)) {
elem match {
case _ if (elem % 2 == 0) => println(elem + " is even.")
case _ => println(elem + " is odd.")
}
}
case
case
类是一种特殊的类,它们经过优化以被用于模式匹配
当定义一个类时,如果在class
关键字前加上case
关键字,则该类称为case
类
Scala
为case
类自动重载了许多实用的方法,包括toString
、equals
和hashcode
方法
Scala
为每一个case
类自动生成一个伴生对象,其包括模板代码
-
1个
apply
方法,因此,实例化case
类的时候无需使用new
关键字 -
1个
unapply
方法,该方法包含一个类型为伴生类的参数,返回的结果是Option
类型,对应的类型参数是N元组,N是伴生类中主构造器参数的个数。Unapply
方法用于对对象进行解构操作,在case
类模式匹配中,该方法被自动调用,并将待匹配的对象作为参数传递给它
假如自定义一个如下的case
类
case class Car(brand :String,price: Int)
那么编译器自动生成的半生对象是
object Car{
def apply(brand:String,price:Int)= new Car(brand,price)
def unapply(c:Car):Option[(String,Int)]=Some((c.brand,c.price))
}
object CaseTest {
def main(args: Array[String]): Unit = {
val myBYDCar = Car04("BYD", 89000)
val myBMWCar = Car04("BMW", 1200000)
val myBenzCar = Car04("Benz", 1500000)
for (car <- List(myBYDCar, myBMWCar, myBenzCar)) {
car match {
case Car04("BYD", 89000) => println("Hello, BYD!")
case Car04("BMW", 1200000) => println("Hello, BMW!")
case Car04(brand, price) => println("Brand:" + brand + ", Price:" + price + ", do you want it?")
}
}
}
}
case class Car04(brand: String, price: Int)
包
为了解决程序中命名冲突的问题,Scala
也采用包来层次化、模块化的组织程序
package autodepartment
class MyClass
为了在任意位置访问到MyClass
,则需要写成下列格式autodepartment.MyClass
通过在关键字package
后面加大括号,可以将程序的不同部分放在不同的包里。这样可以实现包的嵌套,相应的作用域也是嵌套的
package xmu {
package autodepartment {
class ControlCourse{
...
}
}
package csdepartment {
class OSCourse{
val cc = new autodepartment.ControlCourse
}
}
}
使用import
自居来引用包成员
import xmu.autodepartment.ControlCourse
class MyClass{
var myos=new ControlCourse
}
使用通配符(_)
引入类或对象的所有成员
import scala.io.StdIn._
var i=readInt()
var f=readFloat()
var str=readLine()