scala面向对象综述
一、Scala面向对象编程综述
1.1 Scala是纯粹的面向对象的语言
以Java为例, Java并不是一门纯面向对象的语言,其允许非对象值的存在,也允许不属于任何对象的静态字段和方法存在。
Scala是纯粹的面向对象的语言,每个值都是对象,每个操作都是方法调用。
1.2 Scala大量重用了 Java中的类型
Scala与 Java完全兼容, Scala程序会被编译成 Java字节码,访问 Java字段,继承 Java类,实现 Java接口都不需要特别的语法,实际上 Scala也使用了大量的Java库代码。比如 Scala String类与 java.lang.String一样。
1.3 Scala OOP比较 Java OOP的主要差异
- Scala取消了接口( Interface),新增了类似的 特质 概念( Trait)
- Scala取消静态字段和方法,新增 单例对象 的概念( Singleton Object)
- Scala新增了 样例类 case class)
二、类和对象
- 类是对对象的抽象模板,描述了该类对象可以拥有的属性和方法
- 对象是类 的具体实例
- 类和对象最明显的 区别:类不占用内存,对象占用内存
2.1类的定义
Scala与 Java创建普通类的方式基本一样:
class 类名 (参数列表 ){
辅助构造器
成员变量
成员方法
}
- Scala提出主构造器与辅助构造器的概念,类似 Java构造方法。主构造器是 “类名 (构造参数列表 )” ,辅助构造器 this(构造参数列表 )” ,辅助构造器类似于 Java中的构造方法重载,所有构造器都没有返回值。注意辅助构造器必须间 接或直接调用主构造器。
- Scala中,“ this” 是关键字,用于引用当前对象。可以使用 this调用实例变量、方法、构造器。
- Scala类成员默认为 public ,也可修改为 private 和 protected 。
- Scala类中无法定义静态成员和方法,因为没有 static关键字。
- 类中可以有字段和方法,统称为成员变量。字段可以用var或 val定义,都是指向对象的变量。
示例: 创建一个 Studnet 类
class Student() { //默认无参。括号可以不加 默认有一个无参构造器
//定义成员变量 //使用var修饰自带了get、set方法, val只有get方法
var name:String="张三" //设置name默认值为 张三
var age:Int= _ //默认为0
var gender:String = _ //默认null
var banji:Int = 1 //设置班级默认为1
//定义一个辅助构造器1,设置 name,age属性
def this(name:String,age:Int)={
//辅助构造器必须从调用其他构造器开始
this()
this.name=name
this.age=age
}
//定义一个辅助构造器2,设置gender属性
def this(gender:String){
this("李四",18) //可以在this中设置name,age的默认值
this.gender =gender
}
//定义一个成员方法
def study()={
println(name+"喜欢学习scala")
}
}
object Test01{ //main方法只能写在object中
def main(args: Array[String]): Unit = {
//使用默认无参的构造方法
val stu1: Student = new Student()
println(stu1.name)
println(stu1.age)
println(stu1.gender)
stu1.study()
//控制台输出:
/*张三
0
null
张三喜欢学习scala
*/
//调用辅助构造器1
val stu2: Student = new Student("小明", 22)
println(stu2.name)
println(stu2.age)
println(stu2.gender)
stu2.study()
//控制台输出:
/*小明
22
null
小明喜欢学习scala
*/
//调用辅助构造器2
val stu3=new Student("男")
println(stu3.name)
println(stu3.age)
println(stu3.gender)
stu3.age=18
stu3.study()
//控制台输出:
/*李四
18
男
李四喜欢学习scala
*/
}
}
除了上面介绍的类定义方法,还有一种更简便的创建类的方式:
class Dog(var name: String,var age:Int){ //自动生成类的属性
def cry()=println("wow ...")
}
object Dog {
val dog = new Dog("Harry",2)
dog.name="Wang" //编译错误,需要将val类型改成var
dog.age=3 //编译通过
}
注: 主构造器中,使用val的定义的变量自动生成 getter var定义的变量自动生成 getter&setter。在 Scala中,严格来说是没有 getter和 setter这个说法,使用了“ value”和 value_=”两个方法来分别代替了 getter和 setter。如下所示:
class Counter(var value:Int)
class Counter{
private var privateValue = 0 //私有变量,外界无法直接访问
def value = privateValue //定义一个方法,代替 getter
def value_= ( newValue : Int ){ // value_= 是方法名字 ,代替 setter
value = newValue //将 newValue 赋值给 value,类似于set方法
} //注意, scala中默认方法是 public的
}
2.2 样例类
样例类(case class) 在匹配模式中经常使用到,当一个类被定义成为case类后,Scala会自动创建一个伴生对象,实现了 apply 与 unapply 等其他方法,方便很多。而 普通类 只有在伴生对象中定义apply和unapply方法才能够利用伴生对象的方式创建对象和模式匹配
①:默认实现 apply 方法(apply方法通常称为注入方法,在伴生对象中做一些初始化操作,不需要new关键字就能创建该类对象,创建对象的参数列表不需要和构造器的参数列表统一)
②:默认实现 unapply 方法(unapply通常称为提取方法,使用unapply方法提取固定数量的参数来进行模式匹配,unapply方法会返回一个序列(Option),内部产生一个Some对象,Some对象存放一些值)
③:默认实现类构造参数的 getter 方法(构造参数默认被声明为 val ),但是当构造参数声明是 var 类型的,默认会实现 setter 和 getter 方法(不建议将构造参数类型声明为 var )
④:默认实现 toString ,equals,copy 和 hashCode 等方法
示例:
定义一个普通类 People :
class People(val name:String,var age:Int,var sex:String){
}
object PeopleDemo{
//注入方法apply
def apply(name:String,age:Int,sex:String): People= new People(name,age,sex)
//提取方法unapply
def unapply(people: People): Option[(String,Int,String)] = {
if (people == null){
None
}else{
Some(people.name,people.age,people.sex)
}
}
def main(args: Array[String]): Unit = {
//创建对象
val p = People("milk",18,"male") //省略的new关键字
//unapply方法结合匹配模式使用
p match {
case People("milk",_,_) =>println("Hello,milk")
case _ => println("not such People")
} //控制台打印: Hello,milk
println(p.name) //打印:milk 默认实现了getter方法
// p.name = "Jack" 报错,因为构造参数声明为val类型,所以没有实现setter方法
}
}
将 People 定义为 样式类 我们可以这样写:
case class People(val name:String,val age:Int,val sex:String){
}
object PeopleDemo { //此处为非伴生对象
def main(args: Array[String]): Unit = {
//创建对象
val p = People("milk",18,"male") //省略的new关键字
val p1 = People("Tom",20,"female")
//unapply方法结合匹配模式使用
p match {
case People("milk",_,_) =>println("Hello,milk")
case _ => println("not such People")
} //控制台打印: Hello,milk
println(p.name) //打印:milk 默认实现了getter方法
println(p1.name) //Tom
// p.name = "Jack" //报错,因为构造参数声明为val类型,所以没有实现setter方法
}
}
2.3 单例对象Object
- Scala中没有java里面的静态类、静态成员、静态方法,但是scala提供了Object对象,类似于java静态类,,它的成员、它的方法都默认是静态的。
本 - 本质上, 单例对象是一种特殊的类,有且只有一个实例 。单例对象在第一次使用时被创建,所有成员都可以直接访问。
- **main()**方法必须定义在单例对象中, Object 对象继承 App(内置特质)会默认提供main()方法,不需要在写main()方法
- 小结:在
Scala中,类和单例对象的差别在于,单例对象不能带参数,而类可以。因为单例对象无法使用 new关键字实例化,也就没有办法为它传递实例
2.4 伴生
①:伴生关系
限制条件:object(单例对象)与 class(普通类)同名且在一个文件中
示例:
//伴生类
class Student(n: String, a: Int) {
private var name = n //私有变量,伴生对象可以访问
private var age = a
}
//伴生对象
object Student {
def apply(n: String, a: Int): Student = new Student(n, a)
def main(args: Array[String]): Unit = {
val stu=Student("Jason",9) //通过伴生对象的 apply()方法创建实例
println(stu.name) //Jason
}
}
一旦建立伴生关系,伴生对象与伴生类可相互访问私有成员。伴生对象主要为伴生类提供一种静态成员访问的途径。
②:伴生类
指在伴生关系中的伴生类,在class(伴生类)中访问 object(伴生对象)的
私有属性,使用“ object名 .成员”
③:伴生对象
指在伴生关系中的单例对象,在object(伴生对象)中访问 class(伴生类的私有属性,必须通过 class实例对象访问,如上面的“ stu.name”
2.5 特质
- 特质封装了字段和方法的定义,并可以混入到类中重用。每个类只能继承一个超类,但可以混入多个特质 。定义特质使用 trait 关键字,其它与类定义相似,使用extends或 with关键字可将特质混入类中。
- 对象也可以使用 with混入特质,称为动态混入
- 特质类似于带有具体方法的Java接口,在特质中实现一次方法,而不再需要在每个混入特质的类中重新实现。
- 特质也像抽像类,但抽象类只能继承一次,而特质可以混入多次
- 特质中未被实现的方法默认就是抽象方法
- 重写特质的抽象方法时, 不需要 override 关键字