Scala基础6——第6章:面向对象

本文详细介绍了Scala中的面向对象编程概念,包括包的管理、类和对象的定义、封装、构造器、继承、多态、抽象类、特质、类型检查与转换,以及枚举类和应用类的使用。通过实例解析了各种特性,展示了Scala如何实现面向对象编程的灵活性和强大功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第6章、面向对象

6.1 Scala包

(1)基本语法

​ package 包名

(2)包的三大作用(和java一样)

​ ① 区分相同名字的类

​ ② 当类很多,可以很好的管理类

​ ③ 控制访问范围

6.1.1 包的命名

1)命名规则

​ 值包含数字、字母、下划线。不能以数字开头,也不要使用关键字

2)命名规范

​ 小写字母+小圆点

​ com.公司名.项目名.业务名

6.1.2 包说明

​ 包名和源文件不需要在同一个地址

​ 用.来分割表示包的层级关系

​ scala的包可以使用Java的风格,也可以使用另一种风格。scala的风格则可以在一个文件中定义多个包,但是非必要不使用

// scala的另一种包表示方式
package com{
    package baidu{
        package scala{
            
        }
    }
}
// 用嵌套风格定义包
package com{
    // 在外层包中定义单例对象
    import com.baidu.scala.Inner
    object Outer{
        var out:String = "out"
        def main(args:Array[String]):Unit={
            print(Inner) // 需要导入内部包 com.baidu.scala.Inner
        }
    }
    
    package baidu{
        package scala{
        	// 内层包中定义单例对象
            object Inner{
                
                def main(args:Array[String]):Unit={
                    println(Outer.out)
                	Outer.out = "outer"
                    println(Outer.out)
                }
                
            }
        }
    }
}


// 在同一文件中定义多个包
package aaa{
    package bbb{
        def main(args:Array[String]):Unit={
            println("hello")
        }
    }
}

6.1.3 包对象

​ 在Scala中可以给每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object共享

package object chapter06{
    // 定义当前包共享的属性和方法
    val commonValue = "张三"
    def commonMethod():Unit={
      	println(s"我们在${commonValue}家学习")  
    }
}
package chapter06 //同一个包名,chapter06
object Test02{
    def main(args:Array[String]):Unit={
        commonMethod() // 同一包下都可以访问
        println(commonValue)
    }
}
package chapter06{// 嵌套定义的包chapter06
    object Test02{
        def main(args:Array[String]):Unit={
            commonMethod() // 同一包下都可以访问
            println(commonValue)
        }
    }
}

6.1.4 导包说明

1)和Java一样,使用import导入

2)局部导入:什么时候使用,什么时候导入

3)通配符导入 import java.util._

4)给类起别名: import java.util.{ArrayList=>JL}

5)导入相同包的多个类: import java.util.{HashSet,ArrayList}

6)屏蔽类: import java.util.{ArrayList=>_,_}

7)导入包的绝对路径: new _root_.java.util.HashMap

6.2 类和对象

类:可以看出一个模板

对象:表示具体的事物

6.2.1 定义类

1)回顾:Java中的类

​ 如果类是public的,则必须和文件名一致

​ 一般,一个 java有一个public类

2)基本语法

[修饰符] class 类名{
    类体
}

​ scala的类,如果不写修饰符,默认是public

object Test03{
    def main(args:Array[String]):Unit={
        val student = new Student()
        // println(student.name) //!!! 不能访问private属性
        println(student.age) 
        println(student.sex)
        student.sex = "female"
        println(student.sex)
        
    }
}

// 定义一个类
class Student{
    //定义属性
    private var name2:String = "李四"   
    @BeanProperty  //自动设置get、set方法
    var age:Int = 18
    var sex:String = _ // 定义sex的初值为空 
    
    
}

6.3 封装

​ 把抽象的数据和数据的操作封装在一起

(1)将属性的私有化

(2)提供get、set方法 使用@BeanProperty 生成

6.3.1 访问权限

​ (1)在Java中分为public、private、protected和默认

​ (2)在Scala中的默认访问权限为public,但Scala中没有public关键字

​ (3)private为私有权限,只在类的内部和伴生对象中可用

​ (4)protected为受保护权限,Scala只能在同类和子类中访问,同包不能访问

​ (5)private[包名] 只针对指定包名下的类可以访问

package chapter06
object Test04{
    def main(args:Array[String]):Unit={
        // 创建对象
        val person:Person = new Person()
        //person.idCard //!!! 私有属性无法访问
        //println(person.name) //!!! protected无法访问
    	println(person.age) // 可以访问
        println(person.sex)
        
        
        val worker:Worker = new Worker() // 定义一个worker
        worker.printInfo()
    }
}

// 定义一个父类
class Person{
    private var idCard:String = "12343213"
    protected var name:String = "张三"
    var sex:String = "男" // 默认为public
    private[chapter06]  var age:Int = 18 // 只能在chapter06下才能访问
    
    def printInfo():Unit={
        println(s"Person:${idCard},${name},${sex},${age}")
    }
}


// 定义一个子类
class Worker extends Person{
    override def printInfo():Unit={
        println("worker")
        //println(idCard) //!!! 报错,私有属性子类不能访问
        name = "bob"
        age = 25
        sex = "male"
    }
}

6.3.2 构造器(构造方法)

1)基本语法

class 类名(形参列表){//主构造器
    def this(形参列表){
        // 辅助构造器,需要调用主构造器
    }
    
    def this(形参列表){
        // 辅助构造器可以有多个,可有可无
    }
}
object Test05{
    
    def main(args:Array[String]):Unit={
        val student1 =new Student1()
        student1.Student() // 调用Student方法
        
        val student2 =new Student1("张三")
        val student3 =new Student1("张三",20)
    }
    
}

// 定义一个类
class Student1(){ // 主构造器
    // 定义属性
    var name:String = _ // 默认值
    var age:Int = _
    
    println("1. 主构造方法被调用")
    
    // 辅助构造方法
    def this(name:String){
        this() // 直接调用主构造器
        println("2. 辅助构造方法被调用")
        this.name = name
        println(s"name $name , age: $age")
    }
    
    def this(name:String, age:Int){
        // 调用之前的辅助构造器
        this(name)
        this.age = age
        println(s"name $name , age: $age")
        
    }
    
    // !!!这不是构造方法
    def Student1()Unit={
        println("这不是构造方法,是普通方法")
    }
    
}

6.3.3 构造器参数

1)说明

​ Scala的主构造器参数包括三种类型:

​ (1)未用任何修饰符修饰,该参数就是一个局部变量

​ (2)var修饰参数,作为类的成员属性使用,可以修改

​ (3)val修饰参数,作为类只读属性使用,不能修改

object Test06{
    def main(args:Array[String]):Unit={
    	val student2 = new Student2()
        student2.name = "张三"
        student2.age = 18
        println(s"student2:name=${student2.name}")
        
        
        val student3 = new Student3("张三",12)
        println(student3.age)
        println(student3.name)
        
        val student4 = new Student4("张三",20)
        println(student4.age) 
        student4.printInfo()
        
        val student5 = new Student5("李四",21)
        println(student5.age)
        
        val student6 = new Student6("张三",22,"学校")
        println(student6.school)
        
    }
}


// 定义类
// 无参构造器
class Student2{
    // 单独定义属性
    var name:String = _
    var age:Int = _
}


// 定义构造器,构造器的参数name、age
class Student3(var name:String, var age:Int){
    // 不需要定义name、age了
}

// 主构造器参数无修饰
class Student4(_name:String, _age: Int){
    
    var name:String = _name
    var age:Int = _age
    
    def printInfo(){
        println(name)
        println(age)
    }
}



class Student5(val name:String, val age:Int){
    // 不需要定义name、age。 但是值不能更改  
}


class Student6(var name:String, var age:Int){
	
    var school:String = _
    
    def this(name:String,age:Int, school:String){
        this(name,age)
        this.school = school
    }
}

6.4 继承

scala只能单继承

构造器调用顺序,父类构造器->子类构造器

1)基本语法

class 子类名 extends 父类名{
    // 类体
}

object Test07{
    def main(args:Array[String]):Unit={
        val student7 = new Student7("张三",12)
        // 输出结果
        // 1. 父类的主构造器调用
        // 3 子类主构造器被调用
        val student77 = new Student("a",20,"std001")
        // 输出结果
        // 1. 父类的主构造器调用
        // 3 子类主构造器被调用
        // 4 子类的辅助构造器调用
    }
}

// 定义一个父类
class Person7 (){
    var name:String = _
    var age:Int = _
    
    println("1. 父类的主构造器调用")
    
    def this(name:String, age:Int){
        this()
        print("2,父类的辅助构造器被调用")
        this.name = name
        this.age = age
    }
    
    def printlnfo():Unit={
        println(s"Person: $name $age ")
    }
}


// 定义一个子类
class Student7(name:String,age:Int) extends Person7{ 
    var stdNo:String = _
    
    println("3 子类主构造器被调用")
    
    def this(name:String , age:Int , stdNo:String){
        this(name,age)
        println("4 子类的辅助构造器调用")
        this.stdNo = stdNo
    }
    
    override def printlnfo():Unit={
        println(s"Person: $name $age $stdNo")
    }
}
// 定义一个子类
class Student7(name:String,age:Int) extends Person7(name,age){  //调用了父类的辅助构造器
    var stdNo:String = _
    
    println("3 子类主构造器被调用")
    
    def this(name:String , age:Int , stdNo:String){
        this(name,age)
        println("4 子类的辅助构造器调用")
        this.stdNo = stdNo
    }
    
    override def printlnfo():Unit={
        println(s"Person: $name $age $stdNo")
    }
}
// 输出结果
// 1. 父类的主构造器调用
// 2,父类的辅助构造器被调用
// 3 子类主构造器被调用
// 4 子类的辅助构造器调用

6.5 多态

​ 一种接口可以有多种不同的实现方式

object Test07{
    
    def main(args:Array[String]):Unit={
        // 定义一个方法
        def personInfo(person:Person):Unit={
            person.printInfo()
    	}  
        personInfo(new Student())
        personInfo(new Teacher()) 
        // 输出结果
        // Student
        // Teacher
    }
}

class Person{ 
    def printInfo(){
        println("Person")
    }   
}


class Student extends Person{
    override def printInfo(){
        println("Student")
    }    
}

class Teacher extends Person{
    override def printInfo(){
        println("Teacher")
    }
}

Scala的多态和Java的多态的区别

​ (1)Java的方法是动态绑定,但是属性是静态绑定

​ (2)Scala的方法是动态般的,属性也是动态绑定


object Test08{
    def main(args:Array[String]):Unit={
        val student:Person8 = new Student8()
        println(student.name) // 属性的动态般的
        student.hello() // 方法的动态般的
        // 输出结果
        // student
        // student
    }
}

class Person8{
    val name:String = "person"
    def hello():Unit={
        println("person")
    }
}

class Student8 extends Person8{
    override val name:String = "student"
    override def hello():Unit={
        println("student")
    }
}

6.6 抽象类

抽象类中可以定义抽象属性和抽象方法

1)基本语法

(1) 定义抽象类: abstract class Person{}
(2) 定义抽象数学 val|var name:String //抽象属性没有初始值
(3) 定义抽象方法 def hello():String // 只声明方法,没有实现

2)继承和重写

​ (1)如果父类为抽象类,则子类需要将属性和方法实现。

​ (2)重写抽象方法可以不用加override关键字

​ (3) 子类对抽象属性进行实现,父类可以用var修饰

​ 抽象类中的val类型,可以赋值,并且不需要重写(val 就相当于常量)

class Test09{
    def main(args:Array[String]):Unit={
        
    }
}

// 定义抽象类
abstract class Person9{
    // 非抽象属性
    val name:String = "person" // 常量可以直接赋值
    // 抽象属性
    var age:Int 
    // 非抽象方法
    def eat():Unit={ println("吃")}    
    // 抽象方法
    def sleep():Unit
}

// 具体的实现子类
class Student9 extends Person9{
    // 实现抽象属性和方法
    var age:Int = 18 // 抽象类中可以省略override
    
    def sleep():Unit= { println("student sleep")}
    
	// 重写非抽象属性和方法
    override val name:String = "student"
    override def eat():Unit={
        super.eat() // 调用父类的eat方法
        println("student eat")
    }

}

6.6.1 匿名子类

​ 并不需要直到这个类叫什么


object Test10{
    def main(args:Array[String]):Unit={
        
        // 定义一个匿名子类,该类继承Person0
        val person:Person10 = new Person10{
            override var name:String = "alice"
            override def eat():Unit = println("person eat")
        }
        
        println(person.name)
        person.eat()
        
    }
}

// 定义抽象类
abstract class Person10{
    var name:String
    def eat():Unit 
}

6.7 单例对象(伴生对象)

​ Scala是完全面向对象的语言,是没有静态属性和方法。

​ 作者认为static不够面向对象,所以将所有的static有关的全部抽取出来,放到object之中

​ 伴生对象和对象同名,且放在同一个文件里

object Test11{
    def main(args:Array[String]):Unit={
        
    }
}


// 定义类
class Student11(val name:String , val age:Int){
    printInfo(){
        print(Student11.school) // 访问静态属性
        println(s"$name , $age ")
    }
}

// 伴生对象
// 名字必须完全一样
object Student11{
    val school:String = "Baidu" // 定义静态属性
}
object Test11{
    def main(args:Array[String]):Unit={
        //val student11 = new Student11("张三",11)//!!!报错
        // 通过静态方法进行new
        val student11 = Student11.newStudent("张三",11)
    
    	// 以下两行代码完全等价
    	val student12 = Student11.apply("张三",12)
       	val student13 = Student11("张三",13) //相当于调用了apply方法。
    }
}


// 定义类, 私有化构造方法,不能进行构造
class Student11 private(val name:String , val age:Int){
    printInfo(){
        print(Student11.school) // 访问静态属性
        println(s"$name , $age ")
    }
}

// 伴生对象
// 名字必须完全一样
object Student11{
    val school:String = "Baidu" // 定义静态属性
    
    // 定义一个类的对象实例的创建方法
    def newStudent(name:String, age:Int):Student11 = {
        new Student11(name,age)
    }
    
    // apply方法, 
    // 调用时Student11.apply(...) , 可以写成Student11()
    def apply(name:String, age:Int):Student11 = {
        new Student11(name,age)
    }
}

6.7.1 单例设模式

​ 通过object实现伴生对象

实现方法1:


object Test12{
    def main(args:Array[String]):Unit={
        val student12 = Student12.getInstance()
        
        val student13 = Student12.getInstance()
    }
}


class Student12 private(val name:String, val age:Int){}

object Student12{
    private val student:Student12 = new Student("alice",18)
    def getInstance():Student12 = student  
}

实现方法二:

object Test12{
    def main(args:Array[String]):Unit={
        val student12 = Student12.getInstance()
        
        val student13 = Student12.getInstance()
    }
}


class Student12 private(val name:String, val age:Int){}

object Student12{
    private var student:Student12 = _ //先给null
    def getInstance():Student12 = {
    	if(student == null){
            // 如果没有对象实例的话,就创建一个
            student = new Student("alice",18)
        }
        student
    
    }  
}

6.8 特质(Trait)

​ Scala中用trait来代替接口。

但是trait中可以有非抽象方法

​ trait替代Java的接口,也是对单继承的补充

6.8.1 特质声明

1)基本语法

trait 特质名{
    // 主体
}

6.8.2 特质基本语法

​ 特质的继承也使用extends关键字

​ 如果有多个特质,就采用with关键字

1)基本语法

没有父类 class 类名 extends 特质1 with 特质2 with 特质3
有父类 class 类名 extends 父类 with 特质1 with 特质2
object Test13{
    
    def main(args:Array[String]):Unit={
        val student:Student13 = new Student13()
        student.sayHello()
        student.study()
        println(student.name)
        
        
    }
}

// 定义一个父类
class Person13{
    val name:String = "person"
    val age: Int = 18
    def sayHello():Unit={
        println("hello "+name)
    }
}

// 定义一个特质
trait Young{
    // 声明 抽象和非抽象属性
    var age:Int
    val name:String = "young"
    // 声明非抽象的方法
    def play():Unit={
        println("young people is playing")
    }
    
    // 抽象方法
    def dating():Unit
    
}

class Student13 extends Person13 with Young{
    
    // 重写父类冲突的属性,否则会报错
    override val name:String = "student"
    
    // 实现抽象方法
    def dating():Unit = println("student13")
    
    def study():Unit = println(s"student $name is studying")
    
    // 重写父类方法
    override def sayHello():Unit={
        super.sayHello()
        println("student say hello")
    }
}

6.8.3 特质的混入

​ 把特质 和 类进行混入,分别继承或者实现

object Test14{
    def main(agrs:Array[String]):Unit={
        val student = new Student14()
        student.increase()
        student.increase()
        
    }
}

// 再定义一个特质
trait Knowledge{
    var amount:Int = 0
    def increase():Unit
}

// 定义一个父类
class Person14{
    val name:String = "person"
    val age: Int = 18
    def sayHello():Unit={
        println("hello "+name)
    }
}

// 定义一个特质
trait Young{
    // 声明 抽象和非抽象属性
    var age:Int
    val name:String = "young"
    // 声明非抽象的方法
    def play():Unit={ println("young people is playing")}
    // 抽象方法
    def dating():Unit
    
}

class Student14 extends Person14 with Young with Knowledge{
    override def increase():Unit={
        amount += 1
        println(s"student $name knowledge increase")
    }
    
    // 重写父类冲突的属性,否则会报错
    override val name:String = "student"
    // 实现抽象方法
    def dating():Unit = println("student13")    
    def study():Unit = println(s"student $name is studying")
    
    // 重写父类方法
    override def sayHello():Unit={
        super.sayHello()
        println("student say hello")
    }
}

动态混入,多继承的匿名子类

object Test14{
    def main(args:Array[String]):Unit={
        // 该匿名子类,既继承了Student14,又实现了Talent
        val studentWithTalent = new Student14 with Talent{
    		override def dancing():Unit = println("student is good at singing")
            
        }
        
    }
}

class Student14{}

trait Talent{
    def dancing():Unit
}

6.8.4 特质的叠加顺序(多继承实现顺序)

​ 特质的多继承执行顺序,从后往前叠加

class Student15 extends Person15 with Knowledge with Talent

​ 如果有同名方法,先调用Talent,再调用Knowledge,再调用Person15


trait Knowledge{
    def increase():Unit={
        println("Knowledge")
    }
}

trait Talent{
    def increase():Unit={
        println("talent")
    }
}

class Person15{
    
}
class Student15 extends Person15 with Knowledge with Talent{
    // 重写同名方法
    override def increase():Unit={
        super.increase() // 输出Talent,从后往前进行叠加
    }
}

6.8.5 多继承的复杂情况

​ 菱形继承,钻石继承

​ 如Sub是A和B的子类, 然后A和B同时是C的子类

object Test15{
  def main(args:Array[String]):Unit={
    val ball = new MyBall()
    print(ball.d())
  }
}



// 定义一个特质Ball
trait Ball{
  def d():String = {
    println("ball")
    "ballxxx"}
}

// 定义颜色特质
trait ColorBall extends Ball{
  var color:String = "red"
  override def d():String ={
    println("color")
    color +" " + super.d()
  } 
}

// 定义种类特质
trait CategoryBall extends Ball{
  var category:String = "foot"
  override def d():String = {
    println("category")
    category + " " + super.d()}
}

// 自定义球类
class MyBall extends CategoryBall with ColorBall{
  override def d():String = {
    "my ball is a "+ super.d()
  }
}
class MyBall extends CategoryBall with ColorBall

// 输出结果
// color
// category
// ball
// my ball is a red foot ballxxx

所以是先调用最右边的Color,然后再调用Category,最后调用共同的父类ball

6.8.5 调用指定的父类方法

object Test15{
  def main(args:Array[String]):Unit={
    val c:CC = new CC()
    c.f()

  }
}


class AA{
  def f(): Unit = println("A")
}

trait BB{
  def f():Unit= println("B")
}

class CC extends AA with BB{
  override def f():Unit={
    super[AA].f() // 指定调用AA父类的f方法
    println("C")
  }
}

6.8.6 特质和抽象类的区别

​ (1)优先使用特质trait,因为trait可以实现多继承

​ (2)如果体现本质,就可以使用抽象类

​ (3)trait中不可使用带参数的构造方法,抽象类可以使用带参数的构造方法

6.8.7 特质自身类型

​ 自身类型可实现依赖注入的功能

​ 在trait可以使用其他的类,把其他的类融入自身。

​ 一个trait只能 融入一个其他的类

基本语法
别名:类名 =>

例子:
_:User =>
abc:User =>

_表示通配符, 
abc并没有本质的意思
object Test15{
  def main(args:Array[String]):Unit={
    val user:RegisterUser = new RegisterUser("zhangsan","123")
    user.insert()
  }
}

// 定义一个用户类
class User(val name:String , val password:String){}

class User2(){
  val age = 12
}

//
trait UserDao{
  // 把User类 融入 UserDao类,
  _:User =>

  // 向数据库插入数据
  def insert():Unit = {
    println("插入数据库: " + this.name)
  }
}

// 定义注册用户类
class RegisterUser(name:String, password:String) extends User(name,password) with UserDao{}

// 输出结果
// 插入数据库: zhangsan

6.9 扩展

6.9.1 类型检查和转换

1)说明

obj.isInstanceOf[T] 判断obj是不是T类型
obj.asInstanceOf[T] 将obj强制转换为T类型
classOf 获取对象的类型
object Test17{
    def main(args:Array[String]):Unit={
        val student:Student17 = new Student17("alice",18)
        student.study()
        student.sayHi()
        println(student.isInstanceOf[Student17])// true
        println(student.isInstanceOf[Person17])// true
        
        val stu:Person17 = new Student17("alice",20)
        stu.sayHi()
        println(stu.isInstanceOf[Student17])// true
        println(stu.isInstanceOf[Person17])// true
        val newStudent = stu.asInstanceOf[Student17] // 强制类型转换
        
        
        val person:Person17 = new Person17("alice",20)
        println(person.isInstanceOf[Student17])// false
        println(person.isInstanceOf[Person17])// true
        
        println(classof[Person17])
    }
}


class Person17(val name:String , val age:Int){
    def sayHi():Unit={
        println("hi from person " + name)
    }
}


class Student17(name:String , age:Int) extends Person17(name,age){
    def sayHi():Unit={
        println("hi from student " + name)
    }
    
    def study():Unit={
        println("student study")
    }
}




6.9.2 枚举类和应用类

1)说明

​ 枚举类: 需要继承Enumeration

​ 应用类:需要继承App

// 定义枚举类对象

object Test18{
    def main(args:Array[String]):Unit={
    	println(WorkDay.Monday)
        // 输出 Monday
    }
}


object WorkDay extends Enumeration{
    val MONDAY = Value(1,"Monday")
    val TUESDAY = Value(2,"Tuesday")
    
}
// 定义一个应用类
// 应用类不需要定义main方法
object TestApp extends App{
    println("app start")  
    
    type MyString = String // 给类别起别名
    val a:MyString = "abc"
    
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值