scala学习--面向对象(OOP)

类(class)

  • 类通过class关键字定义
  • 类通过new关键字创建实例
  • 类拥有成员变量和方法
  • 类的成员默认为public,也支持private,protected
  • 类中无法定义静态成员变量和方法
  • 类无需明确定义构造方法,通过构造参数列表声明为类的一部分

构造器:

//Book后面的括号如果没有参数可以省略,为类的主构造器
class Book(){
  var title:String=""  //成员变量
  var author:String=""
  //声明类的辅助构造器
  def this(titlt:String,author:String)={
    this()   //第一句必须调用其它构造器   这里调用的是主构造器
    this.author=author
    this.title=titlt
  }
  //成员方法
  def show(title:String,author:String)={
    println("书名是:"+title+"作者是:"+author)
  }
}

类的实例化

object Book{
  def apply(titlt: String, author: String): Book = new Book(titlt, author)

  def main(args: Array[String]): Unit = {
    val book1 = Book("hello","zhangsan")
    val book2 = Book("hello1","zhangsan1")
    val book3 = Book("hello2","zhangsan2")
    book1.show(book1.title,book1.author)
  }
}

类的继承

使用关键字“extends”实现继承
子类重写父类方法必须使用“override”关键字

class Story extends Book {
  override def show(title: String, author: String): Unit = {
    println("小说的名字是:"+title+"作者是:"+author)
  }
}

抽象类(abstract)

  • 抽象类可以包含未实现的方法,即抽象方法
  • 抽象类无法实例化
  • 抽象类使用“abstract”关键字修饰
  • 子类重写父类抽象方法时,“override”关键字可选
  • 子类重写父类非抽象方法,“override”关键字必写
  • 只要是重写父类的方法,不管是不是抽象方法,都加上override准没错
//创建一个父类
abstract class Shape {
  //写一个抽象方法
  def draw():Unit

  //写一个非抽象方法
  def write={
    println("写代码")
  }
}
//创建一个子类继承
class Circle extends Shape {
  override def draw(): Unit = {
    println("画一个圆")
  }
}

//单例对象 main方法必须定义在object中 无法定义在class中
object Test3{
  def main(args: Array[String]): Unit = {
    val circle = new Circle
    circle.draw()
    circle.write
  }
}

单例对象(object)

Scala的类中无法定义静态成员,即无static关键字。如何像Java一样表达类的静态成员变量、成员方法与静态代码块?

scala解决方案:单例模式

  • 使用“object”关键字声明,可包含变量、方法与代码定义
  • 单例对象中的成员变量、成员方法通过单例对象名直接调用
  • 单例对象第一次被访问时初始化,并执行全部代码块
  • 单例对象不能new,且无构造参数
  • 程序入口main()方法必须定义在单例对象中
  • 单例对象与同名类定义在同一文件中时形成绑定关系–伴生(Companion)
//创建一个子类继承
class Circle extends Shape {
  override def draw(): Unit = {
    println("画一个圆")
  }
}

//单例对象 main方法必须定义在object中 无法定义在class中
object Test3{
  def main(args: Array[String]): Unit = {
    val circle = new Circle
    circle.draw()
    circle.write
  }
}

伴生(Companion)

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

object Student {

  //apply方法创建一个Student对象,后面是用的时候不用new
  def apply(n: String, a: Int): Student = new Student(n, a)

  def main(args: Array[String]): Unit = {
    val stu1 = Student("zhangsan", 12)
    println(stu1.age)
    println(stu1.name)
    //自带apply,新建对象不用new
    val list = List(1, 2, 3, 4)
  }
}

特质(trait)

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

//创建一个类实现这个特质
class Dog(val name: String) extends Pet{
  //重写特质的方法
  override def cry()=println("wow ...")
}
  
//创建一个单例对象用来测试
  object Test001 extends App {
    val dog = new Dog("Harry")
    val animals = ArrayBuffer.empty[Pet]
    animals.append(dog)
    animals.foreach(pet => {println(pet.name);pet.cry()})  // Prints Harry wow ...
  }

混入特质

  • 当某个特质被用于组合类时,被称为混入
  • 一个类只能有一个父类但是可以有多个混入(分别使用关键字extends和with)
//定义一个抽象类
abstract class A{
  val message:String
}
//B继承抽象类A(普通类继承抽象类必须要实现抽象方法或者变量)
class B extends A{
  override val message: String ="this is B"
}
//定义一个特质(继承抽象类不需要实现抽象方法或者变量)
trait C extends A{
  def mes_toUpper=message.toUpperCase()
}

class D extends B with C


object MixinTrait extends App {
  val d = new D
  println(d.message)
  println(d.mes_toUpper)
}

动态混入特质

class Drawing {
  //实现动态混入
  this:Shaping=>
  def start():Unit=draw()
}

trait Shaping{
  def draw()={

  }
}

trait Square extends Shaping{
  override def draw(): Unit = println("画一个方")
}

trait T extends Shaping{
  override def draw(): Unit = println("画一个三角")
}

object Test08 extends App{
  //在创建对象的时候混入
  private val d1 = new Drawing with Square
  d1.start()
  private val d2 = new Drawing with T
  d2.start()
}
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
  }
}

object Test002 extends App {
  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被认为是不同的对象
  
}

样例类(case class)

样例类常用于描述不可变的值对象(Value Object)
当一个类被声名为case class的时候,scala会帮助我们做下面几件事情:

  • 1、构造器中的参数如果不被声明为var的话,它默认的是val类型的,但一般不推荐将构造器中的参数声明为var。
  • 2、自动创建伴生对象,同时在里面给我们实现子apply方法,使我们在使用的时候可以不直接使用new创建对象。
  • 3、伴生对象中同样会帮我们实现unapply方法,从而可以将case class应用于模式匹配。
  • 4、实现自己的toString、hashCode、copy、equals方法
  • 除此之此,case class与其它普通的scala类没有区别
case class Student(name:String,age:Int)      //定义样例类
val stu=Student("Jason",19)      //创建样例类的实例,无需new关键字
println(stu.name)       //访问对象属性
  • 样例类构造参数默认声明为“val”,自动实现类构造参数的getter
  • 样例类构造参数声明为“var”时,自动实现类构造参数的setter和getter
  • 样例类自动创建伴生对象
  • 样例类自动实现的其他方法
    toString()、equals()、copy()、hashCode()
    伴生对象中的apply()、unapply()

实例样例类:

//声明一个样例类  属性是name和age
case class Student(name:String,age:Int)

//创建一个测试类
object Test003{
  def main(args: Array[String]): Unit = {
    //样例类会自动创建apply方法,所以创建实例的时候不用new
    val stu = Student("zhangsan",19)
    //样例类自动实现的一些方法
    println(stu.toString)
    val stu1=stu.copy()
    println(stu1.eq(stu))
    println(stu1.equals(stu))
  }
}

结果:

Student(zhangsan,19)
false
true

样例类与枚举

object Weekday extends Enumeration {
  val Mon,Tue=Value   //枚举值从0开始计数
}

object Test09{
  def main(args: Array[String]): Unit = {
    println(Weekday.Mon)
    println(Weekday.Mon.id)  //枚举的使用
  }
}

样例类与枚举区别
1)枚举更简单,代码更少
2)样例类的字段比枚举的值更强大
3)样例类可扩展

泛型类

泛型类指可以接受类型参数的类,定义泛型类使用"[]"

型变

协变

class Test[+T]
[]中使用+,表示协变,当有两种类型A和B有继承关系,B是A的子类,那么泛型类Test[+B]就是Test[+A]的子类

逆变

class Test[-T]
[]中使用+,表示逆变,当有两种类型A和B有继承关系,B是A的子类,那么泛型类Test[+A]就是Test[+B]的子类

不变

class Test[T]
那么无论AB什么关系 都不影响Test类

©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页