Scala 基础 :面向对象(下篇)
Posted 百思不得小赵
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scala 基础 :面向对象(下篇)相关的知识,希望对你有一定的参考价值。
在之前的文章中总结了Scala面向对象模块基础的内容,接下来学习面向对象的高阶内容。
一、抽象类
如何定义?
// 定义抽象类
abstract class 类名
// 定义抽象属性 不赋初始值
val|var 变量名: 类型
// 定义抽象方法 只声明,不实现
def 方法名(): 返回值类型
- 如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类
- 重写非抽象方法需要用
override
修饰,重写抽象方法则可以不加override
- 子类中调用父类的方法使用
super
关键字 - 子类对抽象属性进行实现,父类抽象属性可以用
var
修饰; - 子类对非抽象属性重写,父类非抽象属性只支持
val
类型,而不支持var
。因为var
修饰为可变量,子类继承后可以直接使用修改,没有必要重写。
举个栗子:
// 定义抽象类
abstract class Person
// 定义非抽象属性
val name: String = "person"
// 抽象属性
var age: Int
// 非抽象方法
def eat(): Unit =
println("Person eat")
// 抽象方法
def sleep(): Unit
class Student extends Person
// 实现抽象属性和方法
var age: Int = 18
def sleep(): Unit =
println("student sleep")
// 重写非抽象属性和方法
override val name: String = "Student"
override def eat(): Unit =
super.eat()
println("Student eat")
匿名子类
和 Java 一样,可以通过包含带有定义或重写的代码块的方式创建一个匿名的子类。匿名子类只针对抽象类和接口。
举个栗子:
object Test10_AnnoymousClass
def main(args: Array[String]): Unit =
// 匿名子类实现
val person = new Person
override var name: String = "alice"
override def eat(): Unit = println("person eat")
println(person.name)
person10.eat()
abstract class Person
var name: String
def eat():Unit
二、单例对象(伴生对象)
Scala是一门完全面向对象的语言,没有静态操作。为了能够和Java语言进行交互,使用单例对象来取代static
关键字的语义,伴生类的静态声明
都可放在伴生对象中。
基本语法:
object 伴生对象名
val country: String="China"
- 编译后会生成两个类,伴生对象是伴生类(类名为对应类后加$符号)的单例对象。
- 单例对象对应的类称之为伴生类,伴生对象的名称应该和伴生类名一致,必须在同一个文件中。
- 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问。
- Scala 中
obj(arg)
的语句实际是在调用该对象的apply
方法,即obj.apply(arg)
。用以统一面向对象编程和函数式编程的风格。 - Scala底层对于伴生对象的
apply
方法进行了优化,调用时可以省略方法名,直接使用单例对象的名称+调用apply方法的参数
-
当使用
new
关键字构建对象时,调用的其实是类的构造方法,当直接使用类名构建对象时,调用的其实时伴生对象的apply
方法举个栗子:
// 伴生类
// 构造器私有化
class Student private(val name: String, val age: Int)
def printInfo(): Unit =
println(s"Student11: $name $age $Student11.school")
// 伴生对象
object Student
// 看作静态的属性
val school: String = "清华"
// 定义类对象实例创建的方法
def newStudent(name: String,age: Int): Student11 = new Student11(name,age)
def apply(name: String, age: Int): Student11 = new Student11(name, age)
object Test11_Object
def main(args: Array[String]): Unit =
val student = Student.newStudent("alice", 12)
student.printInfo()
val student1 = Student.apply("haha", 12)
val student2 = Student("lolo", 34)
student2.printInfo()
三、特质
如何定义特质?
trait 特质名
// 代码块
- Scala 语言中,采用特质
trait
(特征)来代替接口的概念 - 多个类具有相同的特征时,就可以将这个特征提取出来,用继承的方式来复用
- Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入(
mixin
)多个特质。这种感觉类似于 Java 中的抽象类。
基本语法:
有父类 class extends baseClass with trait1 with trait2 ...
没有父类 class extends trait1 with trait2 ...
- 如果一个类在同时继承特质和父类时,应当把父类写在
extends
后。 - 特质中可以定义抽象和非抽象的属性和方法。
特质叠加引发两种冲突
举个栗子:
class Person
val name: String = "Person"
var age: Int = 18
def sayHi(): Unit =
println(s"hello from : $name")
trait Young
// abstract and non-abstract attribute
var age: Int
val name: String = "young"
// method
def play(): Unit =
println(s"young people $name is playing")
def dating(): Unit
trait Knowledge
var amount: Int = 0
def increase(): Unit =
amount += 1
trait Talent
def increase(): Unit =
println("increase talent")
class Student extends Person with Young with Knowledge with Talent
override val name: String = "alice"
def dating(): Unit =
println(s"Sutdent $name $age is dating")
def study(): Unit = println(s"Student $name is studying")
override def sayHi(): Unit =
super.sayHi()
println(s"hello from : student $name")
override def increase(): Unit =
super.increase()
println(s"studnet $name knowledge increase: $amount")
object Trait
def main(args: Array[String]): Unit =
val s = new Student()
s.sayHi()
s.increase()
s.study()
s.increase()
s.play()
s.increase()
s.dating()
s.increase()
举个栗子:
trait Ball
def describe(): String = "ball"
trait ColorBall extends Ball
val colorBall: String = "red"
override def describe(): String =
colorBall+"-----"+super.describe()
trait CategoryBall extends Ball
val categoryBall: String = "foot"
override def describe(): String = categoryBall+"-----"+super.describe()
// 叠加顺序 MyFootBall -> ColorBall -> CategoryBall -> Ball
class MyFootBall extends CategoryBall with ColorBall
override def describe(): String = "my ball is a" + super.describe()
- 当一个类混入多个特质的时候,scala 会对所有的特质及其父特质按照一定的顺序进行排序,而此案例中的
super.describe(
)调用的实际上是排好序后的下一个特质中的describe()
方法。 - 要调用某个指定的混入特质中的方法,可以增加约束:
super[]
super[CategoryBall].describe()
自身类型
- 自身类型可实现依赖注入的功能。
- 一个类或者特征指定了自身类型的话,它的对象和子类对象就会拥有这个自身类型中的所有属性和方法。
- 是将一个类或者特征插入到另一个类或者特征中,属性和方法都就像直接复制插入过来一样,能直接使用。但不是继承,不能用多态。
举个栗子:
object Test16_TraitSelfType
def main(args: Array[String]): Unit =
val user = new RegisterUser("alice", "1212121")
user.insert()
// 用户类
class User(val name: String,val password: String)
trait UserDao
// 定义自身类型
_: User =>
// 注册用户
def insert():Unit=
println (s" insert into db: = $this.name , $this.password")
// 定义注册用户
class RegisterUser(name: String,password: String) extends User(name,password) with UserDao
_: SelfType =>
,其中_
的位置是别名定义,也可以是其他,_
指代this。插入后就可以用this.xxx
来访问自身类型中的属性和方法了。
抽象类和特质的区别?
四、扩展内容
类型检查和转换
obj.isInstanceOf[T]
:判断obj
是不是T
类型。obj.asInstanceOf[T]
:将obj
强转成T
类型classOf
获取对象的类名。结果是class package.xxx.className
- 获取对象的类:
obj.getClass
枚举类
- 需要继承
Enumeration
。 - 用
Value
类型定义枚举值。
// 定义枚举类
object WorkDay extends Enumeration
val MONDAY = Value(1,"星期一")
val TUESDAY = Value(2,"星期二")
println(WorkDay.MONDAY)
应用类
- 继承App,包装了main方法,就不需要显式定义main方法了,可以直接执行。
object TestApp extends App
println("app start"
定义新类型
- 使用 type 关键字可以定义新的数据数据类型名称,本质上就是类型的一个别名
type SelfDefineType = TargetType
。
type MyString= String
val a: MyString = "abc"
println(a)
本次分享的内容到这里就结束了,希望对大家学习Scala语言有所帮助!!!
以上是关于Scala 基础 :面向对象(下篇)的主要内容,如果未能解决你的问题,请参考以下文章