大家好,我是百思不得小赵。
创作时间:2022 年 7 月 2 日
博客主页: 🔍点此进入博客主页
—— 新时代的农民工 🙊
—— 换一种思维逻辑去看待这个世界 👀
今天是加入CSDN的第1217天。觉得有帮助麻烦👏点赞、🍀评论、❤️收藏
在之前的文章中总结了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"
}
obj(arg)
的语句实际是在调用该对象的 apply
方法,即 obj.apply(arg)
。用以统一面向对象编程和函数式编程的风格。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 特质名 {
// 代码块
}
trait
(特征)来代替接口的概念mixin
)多个特质。这种感觉类似于 Java 中的抽象类。基本语法:
有父类 class extends baseClass with trait1 with trait2 ... {}
没有父类 class extends trait1 with trait2 ... {}
extends
后。特质叠加引发两种冲突
第一种:一个类(
Sub
)混入的两个 trait(TraitA
,TraitB
)中具有相同的具体方法,且两个 trait 之间没有任何关系
如果当前父类和特质里面出现了相同的属性和方法,就会起冲突,必须在当前实现的子类(sub
)中进行重写。
举个栗子:
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()
}
}
第二种:一个类(
Sub
)混入的两个 trait(TraitA
,TraitB
)中具有相同的具体方法,且两个 trait 继承自相同的 trait(TraitC
)
Scala采用了特质叠加的策略来解决这类冲突。
举个栗子:
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()
}
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)
应用类
object TestApp extends App{
println("app start"
}
定义新类型
type SelfDefineType = TargetType
。 type MyString= String
val a: MyString = "abc"
println(a)
本次分享的内容到这里就结束了,希望对大家学习Scala语言有所帮助!!!