大数据基础之Scala——Scala OOP面对对象

基本概念:

  • 类(class)
  • 抽象类(abstract class)
  • 单例对象(object)
  • 特质(trait)
  • 样例类(case class)

类(class)

  • 类通过class关键字定义
  • 类通过new关键字创建实例对象
  • 类拥有成员变量和方法
  • 类的成员默认为public,也支持private、protected
  • 类中无法定义静态成员变量和方法
  • 类无需明确定义构造方法,通过构造参数列表声明为类的一部分
1.类的定义:
  • 构造器
      - 主构造器(带参构造)
      - 辅构造器(无参构造)
  • 成员变量与方法
  • 类的实例化
2.类的继承
  • Scala使用“extends”关键字实现继承
  • 子类重写父类的方法必须使用“override”关键字
3.抽象类
  • 抽象类可包含未实现的方法,即抽象方法
  • 抽象类无法实例化
  • 抽象类使用“abstract”关键字修饰
     -子类重写父类的抽象方法,“override”可选
     - 子类重写父类非抽象方法,“override”必写

单例对象(object)

  • 使用“object”关键字声明,可包含变量、方法与代码定义
  • 单例对象中的成员变量、成员方法通过单例对象名直接调用
  • 单例对象第一次被访问时初始化,并执行全部代码块
  • 单例对象不能new,且无构造参数
  • 程序入口main()方法必须定义在单例对象中
  • 单例对象与同名类定义在同一文件中时形成绑定关系
//定义单例对象
object Blah {
  println("Blah initializing...")
  def sum(l: List[Int]): Int = l.sum
}
def main(args:Array[String]):unit = {
	Blah.sum(List[Int](1, 2, 3, 4, 5))
}

伴生对象:

当你的类需要用到你的对象时,即用到既有实例方法又有静态方法的类.通常我们使用伴生对象完成

  • 单例对象与同名类定义在同一个文件中时形成绑定关系
     -同名类称为单例对象的伴生类
     - 单例对象称为同名类的伴生对象
  • 伴生类与伴生对象可相互访问各自私有成员
  • 伴生对象可为伴生类增加静态成员
//伴生类
class Student(n: String, a: Int) {
  private var name = n    //私有变量,伴生对象可以访问
  private var age = a
}

//伴生对象
// 用伴生对象来代替new
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)
  }
}

特质(trait):

  • Scala中没有接口(interface)的概念
  • 特质用于在类之间共享程序接口和字段,类似Java接口
  • 特质是字段和方法的集合,可以提供字段和方法实现
  • 类和单例对象都可以扩展特质(extends)
  • 特质不能被实例化,因此没有构造参数,类似Java接口
  • 特质使用“trait”关键字定义
  • 实现特质中的方法使用“override”
trait Pet {
  val name: String
  def cry():Unit
}
class Dog(val name: String) extends Pet{
  override def cry()=println("wow ...")
}

val dog = new Dog("Harry")
val animals = ArrayBuffer.empty[Pet]
animals.append(dog)
animals.foreach(pet => {println(pet.name);pet.cry()})  // Prints Harry wow ...

混入特质(mixin):

  • 当某个特质被用于组合类时,被称为混入
  • 一个类只能有一个父类,但是可以有多个混入(分别使用extends和with)

在这里插入图片描述
案例:

class Person{
  val mag:String="person"
  def act()={
    println("person")
  }
}

trait MyFather extends Person{
  override val mag: String = "father"
  override def act()={
    println("father")
  }
}

trait MyMather extends Person{
  override val mag: String = "mather"
  override def act()={
    println("mather")
  }
}

trait MySister extends Person{
  override val mag: String = "sister"
  override def act()={
    println("sister")
  }
}

class MyMutleTrait extends MyFather with MyMather with MySister {
  override val mag: String = "son"
}


object test{
  def main(args: Array[String]): Unit = {
   var mmt = new MyMutleTrait
    println(mmt.mag)
    mmt.act()
  }
}
//最终结果由最右边一个特质决定,如果在特质类中有指定某个属性则按指定属性结果输出,若没有则按照最右边的特质结果输出

最终结果:在这里插入图片描述

动态混入特质:

b和c如果 都应用了某特质,b去实现了该特质的某种方法,c并不会收到影响,完成了解耦而java接口会因为传递性,c会有b实现的方法。

案例:

//书类
class Books {
//冒号前面为别名,后面为该类实例化时必须混入相应的特质或子特质
  eb:EBook=>
  val ctx:String="我是书的内容"
  val name:String="我是书名"

  def seeBook():Unit={
    play()
    println(info())
  }

  def info():String = {
    name+":"+ctx
  }
}

//电子书特质(抽象类)
trait EBook {
  def play():Unit;
}

//两种实现
trait IPad extends EBook{
  override def play(): Unit = {
    println("平板播放")
  }
}

trait Phone extends EBook{
  override def play(): Unit = {
    println("手机播放")
  }
}

//测试类
object MyDemo {
  def main(args: Array[String]): Unit = {
    (new Books() with IPad).seeBook()
  }
}
特质与抽象类的选择
  • 优先使用特质
     - 抽象类只能继承一次
     - 特质可以混入多个
  • 需要使用带参构造方法时,使用抽象类
  • 与Java互操作性
     - 抽象类 与Java完全可以互操作
     - 特质只有在不包含任何实现代码是才可以互操作

内部类:

  • 一个类可以作为另一个类的成员,称为内部类
     - Java内部类是外部类的成员
     - Scala内部类绑定到外部类的对象实例
    案例:
class Graph {
  class Node {
    var connectedNodes: List[Node] = Nil
    def connectTo(node: Node) {
      if (connectedNodes.find(node.equals).isEmpty) {
        connectedNodes = node :: connectedNodes
      }
    }
  }
  var nodes: List[Node] = Nil
  def newNode: Node = {
    val res = new Node
    nodes = res :: nodes
    res
  }
}

//测试类
val g: Graph = new Graph
val n1: g.Node = g.newNode
val n2: g.Node = g.newNode
n1.connectTo(n2)        // legal
val h: Graph = new Graph
val n3: h.Node = h.newNode
n1.connectTo(n3)       // illegal
//n1与n3被认为是不同的类型


//当按照如下写法时n1和n3就可以被认为是同一类型
class Graph {
  class Node {
    var connectedNodes: List[Graph#Node] = Nil
    def connectTo(node: Graph#Node) {
      if (connectedNodes.find(node.equals).isEmpty) {
        connectedNodes = node :: connectedNodes
      }
    }
  }
  var nodes: List[Node] = Nil
  def newNode: Node = {
    val res = new Node
    nodes = res :: nodes
    res
  }
}

样例类:

  • 样例类常用于描述不可变的值对象
case class Student(name:String,age:Int)      //定义样例类
val stu=Student("Jason",19)      //创建样例类的实例,无需new关键字
println(stu.name)       //访问对象属性  

 - 样例类构造参数默认声明为"val",自动实现类构造参数的getter
 - 样例类构造参数声明为"var"时,自动实现类构造参数的setter和getter方法
 - 样例类自动创建伴生对象
 - 样例类自动实现的其他方法
  - toString()、equal()、copy()、hashCode()
  - 伴生对象中的apply()、unapply()
(apply主要是根据传入参数值创建伴生对象,而unapply主要接受一个对象,从对象中提取出相对应的值,主要用于模式匹配中。)

泛型类

  • 泛型类指可以接受类型参数的类,泛型类在集合中被广泛使用
  • 与Java不同,定义泛型类使用“[ ]”
class Stack[T] {
    var elements: List[T] = Nil
    def push(x: T) { elements = x :: elements }
    def top: T = elements.head
    def pop() {
      var t = elements.head
      elements = elements.tail
      t
    }
    def showElements(){
      elements.foreach(x=>print(s"$x "));println()}
  }

类型边界:

  • 在Scala中,类型参数可以有一个类型边界约束
  • 类型上界:将类型限制为另一种类型的子类
     - T<:A 表示类型变量T应该是类型A的子类
     - A是具体类型,T是泛型
  • 类型下界:将类型声明为另一种类型的超类
     - T>:A 表示类型变量T应该是类型A的超类
     -A是具体类型,T是泛型

案例:

//爷爷类
class GrandFather {
}

//父亲类
class Father extends GrandFather{
}

//儿子类
class Son extends Father {
}

//方法类
class MyTest[T<:Father]{
  def abc(t:T)={
    println(t)
  }
}

//测试类
val value = new MyTest[Father]
    value.abc(new Son())             //正确
    value.abc(new GrandFather())     //报错
  }

型变:

  • 协变
    class Foo[+T]
     - 对于两种类型A和B,如果A是B的子类型,那么Foo[A]是Foo[B]的子类型
  • 逆变
    class Bar[-T]
     - 对于两种类型 A 和 B,如果 A 是 B 的子类型,那么 Bar[B] 就是 Bar[A] 的子类型
  • 不变
    class Baz[T]
     - 默认情况下,Scala的泛型类是不变的

案例:

class Card[+T] {
}

//大师类
class Master {
}

//教授类
class Perforess extends Master {
}

//教师类
class Teacher {
}

//方法
class MyDemo {
  def abc(s:Card[Master])={
    println(s)
  }
}

//测试类
object Runs {
  def main(args: Array[String]): Unit = {
    val mt = new Card[Master]
    val pf = new Card[Perforess]
    val th = new Card[Teacher]
    val md = new MyDemo()

    md.abc(mt)    //正确
    md.abc(pf)    //正确
//    md.abc(th)  //报错
  }
}
//因为教授类继承了大师类,所以在方法中可以传入子类作为参数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值