Scala 面向对象

Scala的面向对象特性与Java类似,但语法更丰富。包用于组织类,可以通过包对象共享变量。类和对象是核心,类可以有主构造器和辅助构造器,支持封装,可以通过@BeanProperty注解生成Java兼容的getter/setter。继承是单继承,支持抽象类和特质,特质可以多混入,解决多继承问题。
摘要由CSDN通过智能技术生成

面向对象

Scala 的面向对象思想和Java的面向对象思想的概念是一致的。相对于Java的语法,Scala 更加丰富。

1、Scala 包

1.1、基本语法

package 包名

1.2、Scala包的三大作用(与Java语言一致)

  • 区分相同名字的类
  • 当类很多时,可以很好的管理类
  • 控制访问范围

1.3、包的命名

1.3.1、命名规则

只能包含数字、字母、下划线,但不能用数字开头,也不要使用关键字

1.3.2、命名规范

同Java语言

com.公司名.项目名.业务模块名

1.4、包说明(包语句)

说明:Scala有两种包的管理风格,一种方式和Java语言的包管理风格相同,每个源文件一个包(包名和源文件所在路径不要求必须一致)com.公司名.项目名,另一种风格,通过嵌套的风格表示层级关系:

package com {
	package 公司名{
		package 项目名 {
		
	}
}

嵌套风格特点:

  • 一个源文件可以声明多个package
  • 子包中的类可以直接访问父包中的内容,而无需导包

1.5、包对象

在Scala中可以为每个包定义个同名的包对象,定义在包对象中成员,作为其对应包下所有的class和object的共享变量,可以直接被访问。

1.5.1、定义
package object com{
    val share = "share"
    def shareFunction() = {}
    
}

1.6、导包

  • 和Java语言一致,可以在顶部使用import 导入,在这个文件中的所有类都可以使用
  • 局部导入,什么时候使用,什么使用导入。在其作用范围内都可以使用
  • 通配符导入: import java.util._ (导入该包下的所有类)
  • 给类起名:import java.util.{ArrayList=JL}
  • 导入相同包的多个类: import.java.uil.{HashSet, ArrayList}
  • 屏蔽类:import java.util.{ArrayList=> _,_}
  • 导入包的绝对路径

2、类和对象

类:可以看成一个模板

对象:表示具体的事务

2.1、类的定义

基本语法

[修饰符] class 类名 {}

实例:

  def main(args: Array[String]): Unit = {
    val student = new Student()
    println(student.age)
    println(student.gender)

    student.gender = "male"
    println(student.gender)
  }

}


/**
 *  类的定义
 */
class Student {
  //属性定义
  private val name:String = "merlin"
  //Scala 中提供了一个注解@BeanProperty, 能够自动生成java的get、set方法
  //Scala 中可以使用Java的API,Java 的很多APi都要求有get、set方法,Scala 为了Java提供了@BeanProperty
  //  @BeanProperty 不能作用于被private修饰的属性上
  @BeanProperty
  var age: Int = 10
  //Scala可以使用 _ 为属性赋默认值,但是属性必须是被var修饰, 如果使用val修饰,该属性将无法修改,大概率赋值默认值就没意义了
  var gender: String = _

}

2.2、封装

封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(成员方法),才能对数据进行操作。Java封装实现:

  • 将属性进行私有化
  • 提供公共的get、set方法,用于获取属性值、设置属性值

Scala中不存在public关键字,缺省即为public,底层实际为private,并通过get、set方法对其操作。所以Scala并不推荐将属性设置为private,再为其设置public的get、set方法的做法。但是由于Java很多框架都利用反射调用get、set方法,为了和这些框架兼容,也需要为Scala中的属性添加get、set方法,Scala提供了@BeanProperty注解帮助开发者实现

2.2.1、访问权限
  • Scala中不存在public关键字,缺省即为public
  • private为私有权限,只在类的内部和伴生对象中可用
  • protected为受保护权限,Scala中受保护权限比Java中更严格。同类、子类可以访问,同包无法访问
  • private[包名]增加包访问权限,包名下的其他类也可以使用
2.2.2、构造器

Scala中,类的构造器包括:主构造器和辅助构造器

基本语法:

class 类名(形参列表) { //主构建器
    
    def this(形参列表) { //辅助构造器
    }
    
    def this(形参列表) { //重载辅助构造器
    }
    
}

说明:

  • 辅助构造器,函数的名称:this,可以重载,编译器通过参数的个数以及类型来区分
  • 辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法
  • 构造器调用其他构造器,要求被调用构造器提前声明
2.2.3、构造器参数

Scala类的主构造器函数的形参包括三种类型:未用任何修饰、var修饰、val修饰

  • 未用任何修饰符修饰,这个参数就是一个局部变量
  • var 修饰参数,作为类的成员属性使用,可以修改
  • val 修饰参数,作为类只读属性使用,不能修改

实例:

object Constructor_Demo {

  def main(args: Array[String]): Unit = {
//    val human = new Human()

    val human = new Human("merlin", 23)
    //1、调用主构造函数
    //2、调用辅助构造参数一
    //3、调用辅助构造器二
    //student: merlin, 23

    println("====================分割线====================")

    val programmer = new Programmer
    programmer.age = 23
    programmer.name = "merlin"

    println(s"programmer: name = ${programmer.name}, age = ${programmer.age}")
    val programmer2 = new Programmer2("merlin", 23)
    println(s"programmer2: name = ${programmer2.name}, age = ${programmer2.age}")
    val programmer3 = new Programmer3("merlin", 23)
//    println(s"programmer3: name = ${programmer3.name}, age = ${programmer3.age}")  //error 无法调用参数
    programmer3.printInfo()

    val programmer4 = new Programmer4("merlin", 23)
    println(s"programmer4: name = ${programmer4.name}, age = ${programmer4.age}")



  }


}


//定义一个类
class Human {
  var name: String = _
  var age: Int = _

  println("1、调用主构造函数")

  //定义辅助构造器
  def this(name: String) {
    this()
    this.name = name
    println("2、调用辅助构造参数一")
  }

  //重载辅助构造器,且调用提前声明的构造器
  def this(name: String, age: Int) {
    this(name)
    this.age = age
    println("3、调用辅助构造器二")

    println(s"human: $name, $age")
  }

}


class Programmer {
  var name: String = _
  var age: Int = _
}

//等价与上面定义
class Programmer2(var name: String, var age: Int) {
}


class Programmer3(name: String, age: Int)  {

  def printInfo(): Unit = {
    println(s"programmer3: name = ${name}, age = ${age}")
  }
}


/**
 * 使用 val修饰参数, 使用这个方式创建对象后,属性值无法再修改
 */
class Programmer4(val name: String, val age: Int) {
}

2.3、继承和多态

基本语法:

class 子类名 extends 父类名 {}
  • 子类继承父类的属性和方法
  • scala是单继承

实例:

/**
 * 定义一个父类
 */
class Person() {
  var name: String = _
  var age: Int = _

  println("1、执行父类主构造器")

  def this(name: String, age: Int) {
    this()
    this.name = name
    this.age = age
    println("2、执行父类辅助构造器")
  }


  def printInfo(): Unit = {
    println(s"person name=$name, age=${age}")
  }

}


/**
 * 定义子类
 *  - 继承时,会调用父类的构造器
 */
class Manager(name: String, age: Int) extends Person {
  var company: String = _

  println("3、执行子类主构造器")

  def this(name: String, age: Int,company: String) {
    this(name, age)
    this.company = company
    println("4、执行子类辅助构造器")
  }

  //重写父类方法
  override def printInfo(): Unit = {
    println(s"manager: name=${name}, age=${age}, company=${company}")
  }

}

2.4、 抽象类

2.4.1、抽象属性和抽象方法

基本语法:

  • 定义抽象类:abstract class Person{} ,通过abstract关键字标记抽象类
  • 定义抽象属性:val|var name:String 一个属性没有初始化,就是抽象属性
  • 定义抽象方法:def hello(): String ,只声明而没有实现的方法,就是抽象方法

说明:

  • 只要类中存在抽象属性或抽象方法,那么这个类必须定义为抽象类
  • 子类重写非抽象属性或方法需要加override,实现抽象属性或方法不需要加override
  • 子类重写非抽象属性只支持val修饰的属性,var修饰的属性可变,直接重写赋值即可

实例:

/**
 * 定义抽象类
 *
 */
abstract class Person2 {

  //普通属性
  val name: String = "merlin"
  //抽象属性
  var age: Int

  //普通方法
  def eat(): Unit = {
    println("恰饭")
  }

  //抽象方法
  def sleep(): Unit

}

/**
 * 定义抽象类的实现类
 */
class Student23 extends Person2 {
  //重写普通属性
  override val name: String = "warning"
  //实现抽象属性
  var age: Int = 23

  //重写普通方法
  override def eat(): Unit = {
    println("student eat function")
  }

  //实现抽象方法
  def sleep(): Unit = {
    println("睡觉")
  }

}

2.5、匿名子类

object Anonymous_Demo {
  def main(args: Array[String]): Unit = {
    //匿名子类
    val person = new Person2 {
      override var age: Int = 23

      override def sleep(): Unit = {
        println("匿名子类睡大觉")
      }
    }

    person.sleep()
  }

}


/**
 * 定义抽象类
 *
 */
abstract class Person2 {

  //普通属性
  val name: String = "merlin"
  //抽象属性
  var age: Int

  //普通方法
  def eat(): Unit = {
    println("恰饭")
  }

  //抽象方法
  def sleep(): Unit

}

2.6、单例对象(伴生对象)

Scala语言是完全面向对象的语言,所以Scala中不存在静态的概念。为了与Java语言交互,就产生了一种特殊的对象来模拟类对象。该对象为单例对象若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有”静态“内容都可以放置在它的伴生对象中声明

说明:

  • 单例对象采用object关键字声明
  • 单例对象对应的类称之为伴生类,伴生对象的名称和伴生类名一致,且存在于同一个文件中
  • 单例对象中的属性和方法都可以通过伴生对象名(类名)直接调用访问
  • 伴生对象和伴生类可以相互访问,即使是private修饰的方法和属性
object Companion_Demo {

  def main(args: Array[String]): Unit = {
    val student = Student11.apply("merlin", 23)
    student.printInfo()

    val student2 = Student11("merlin", 23)
    student.printInfo()

  }
}


/**
 * 伴生类
 *   - 私有化构造器,在伴生对象中提供对象实例的创建方法
 */
class Student11 private(val name: String, val age:Int) {

  def printInfo(): Unit = {
    println(s"student11: name=${name}, age=${age}, school=${Student11.school}")
  }
}

/**
 * 伴生对象
 * - 伴生对象提供了一个特殊的apply方法, 通过类名调用时,可以省略这个apply方法名,直接传入参数列表
 * -
 */
object Student11 {
  val school = "south"

  def apply(name: String, age: Int): Student11 = {
    new Student11(name, age)
  }

}

2.7、特质(trait)

Scala语言中,采用特质(trait)来代替Java语言中的接口(interface)概念,也就是说,多个类具有相同的特质是,就可以将这些特质独立出来,采用关键字trait声明。

Scala中的trait中即可以有抽象属性和方法,也可以有普通属性和方法,一个类可以混入(mixin)多个特质,就像Java可以实现多个接口。

2.7.1、特质声明

一个类具有某种特质,就意味着这个类满足了这个特质的所有要素

说明:

  • 类和特质的关系:使用继承的关系
  • 当一个类去继承特质是,第一个连接词是extends,后面是with
  • 如果一个类在同时继承特质和父类时,应当把父类写在extends

基本语法:

trait trait_name {}

class class_name extends 父类 with 特质1 with 特质2 {}

class class_name2 extends 特质1 with 特质2 {}
2.7.2、特质的混入
  • 多特质混入
  • 动态混入
object Trait_Demo502_Mixin {
  def main(args: Array[String]): Unit = {
    val student = new Student502
    student.increase()

    //动态混入
    val student2 = new Student502 with Talent502 {
      override def dancing(): Unit = println("dancing")

      override def singing(): Unit = println("singing")
    }

    student2.dancing()
    student2.singing()
  }
}


trait Knowledge502 {
  var amount: Int = 0
  def increase() : Unit

}

trait Talent502 {
  def dancing(): Unit
  def singing(): Unit
}


/**
 * 多特质混入
 */
class Student502() extends Person501 with Young with Knowledge502 {

  //重写冲突属性Person03
  override val name = "student merlin"


  override def dating(): Unit = println(s"student ${name} dating. ")

  def study(): Unit = println(s"student ${name} study. ")

  override def sayHello(): Unit = println(s"student ${name} say hello")

  //重写特质Knowledge中的抽象方法
  override def increase(): Unit = {
    amount += 1
    println(s"student name=${name} , amount=${amount}")
  }

}

2.7.3、特质叠加

  • 默认super调用的是混入的最后一个特质中的方法

特质叠加中的钻石问题:

当一个类混入多个特质的时候,scala会对所有的特质及其父特质按照一定的顺序进行排序。此处super.describe() 方法调用的实际上是排好序后的下一个特质中的describe()方法

特质叠加顺序:

  1. 列出混入的第一个特质的继承关系,作为临时叠加顺序
  2. 列出混入的第二个特质的继承关系,并将该顺序叠加到临时顺序之前(已出现的不再重复)
  3. 将子类放在临时叠加顺序第一位,得到最终叠加顺序

super指定父类:

super[parent_class_name]

特质与抽象类的区别:

  • 优先使用特质,特质可以多混入,抽象类仅可以单继承
  • 如果需要构造函数参数,使用抽象类。抽象类可以定义带参数的构造器,特质不行

例:

object Trait_Demo504_Superposition {
  def main(args: Array[String]): Unit = {
    val ball = new MyBall
    println(ball.describe()) // red-foot-Ball
  }
}

trait Ball {
  def describe(): String = "Ball"
}

trait ColorBall extends Ball {
  var color = "red"

  override def describe(): String = color + "-" + super.describe()
}

trait CategoryBall extends Ball {
  val category: String = "foot"
  override def describe(): String = category + "-" + super.describe()
}


/**
 * 一个实现类,混入两个继承了同一特质的特质
 */
class MyBall extends CategoryBall with ColorBall {
//  override def describe(): String = super.describe()

  //super指定父类 - super[parentName]
  override def describe(): String = super[ColorBall].describe()
}

2.8、特质自身类型

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

3、拓展

3.1、类型检查与转换

说明:

  • obj.isInstanceOf[T]:判断obj是不是T类型
  • obj.asInstanceOf[T]:将obj强转为T类型
  • classOf获取对象的类名

3.2、枚举类与应用类

枚举类:继承Enumeration

应用类:需要继承App

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值