美文网首页
Scala中的面向对象

Scala中的面向对象

作者: 叩丁狼教育 | 来源:发表于2018-10-29 11:39 被阅读15次

    本文作者:林伟兵,叩丁狼高级讲师。原创文章,转载请注明出处。

    5. 面向对象

    5.1 类的定义[属性和方法]

    可以用class来声明一个类,并用new关键字来创建一个对象。

    对于类中的全局变量,必须在声明的时候指定其默认值,否则就会报错。

    同时可以在类中定义一系列的方法,方法的定义用def 方法名(参数) :返回值 = {方法体}

    class Person {
    
      var name:String = ""
      var age:Int = 0
    
      def printUserInfo(): Unit ={
        println("name = "+name , "age = "+age)
      }
    
      def eat(food: String): String = s"$name is eating $food"
    
    }
    
    object Test{
    
      def main(args: Array[String]): Unit = {
        val person = new Person()
        person.printUserInfo()
        person.name = "张三"
        person.age = 25
        println(person.eat("大闸蟹"))
      }
    
    }
    
    

    对于全局变量,可以用 _ 来表示默认初始值,如下:

    class SimpleClass {
        var a:Int = _
        var b:Double = _
        var c:Float = _
        var d:Long = _
        var e:String = _
        //对于未知类型的数据使用默认值会直接报错,因为无法进行类型推导
        //var f = _
    
        //SimpleClass(0, 0.0, 0.0, 0, null)
        override def toString = s"SimpleClass($a, $b, $c, $d, $e)"
    }
    
    

    有时候为了让全局变量私有,我们可以添加 private[this]

    class Cat{
    
      private[this] var name:String = "Lucy"
    
      def printName(): Unit ={
        println(s"cat name is $name")
      }
    }
    
    #调用
    var cat = new Cat()
    cat.printName
    //cat.name  这里获取不到name这个全局变量
    
    

    5.2 主构造器和辅助构造器

    Scala的构造器和Java的构造器完全不同,Scala的构造器分为主构造器和辅助构造器;

    ​ 主构造器的参数列表直接写在类名(Class)后面,每个类都有一个主构造器(默认是无参构造器)。主构造器与类的定义交织在一起,除了定义的全局变量和方法,其他都是主构造器的内容,代码如下:

    class Teacher(name: String) {
    
      println("teacher start")
    
      var teachAge: Int = 8
      var height:Double = _
      val school:String = "广工"
    
      println("teacher end")
    
      //辅助构造器,第一行必需调用主构造器或者其他已存在的辅助构造器
      //并且只能调用在自己之前定义的其他辅助构造器,而不能调用后面定义的辅助构造器(避免死循环调用)
      //参数不可以用val或var来修饰
      def this(name: String, teachAge: Int) {
        this(name)
        this.teachAge = teachAge
      }
    
      def this(name: String, teachAge: Int, height: Double) {
        this(name,teachAge)
        this.height = height
      }
    
      def teach(): Unit ={
        println(s"$name is teaching ...")
      }
    
    }
    
    //如果将一个主构造器私有,那么客户端是无法获取该对象的
    class Student private(name: String)
    
    object ConstructorDemo {
      def main(args: Array[String]): Unit = {
        val t1 = new Teacher("孔子")
        println(s"teach age is ${t1.teachAge}")
    
        var t2 = new Teacher("老子", 5)
        println(s"teach age is ${t2.teachAge}")
    
        var t3 = new Teacher("孙子", 3,1.65d)
        println(s"teach age is ${t3.teachAge}")
      }
    }
    
    

    5.3 类的继承

    1. 一个类如果想继承其他的类,就必须调用其构造器,无论主构造器还是辅助构造器;在实例化该类的时候,首先会调用父类的构造器,再调用本身的构造器。

    2. 构造器传入的参数默认为val类型的数据,类的内部无法修改变量值,只能获取。

    class SeniorTeacher(name: String, desc: String,teachAge: Int) extends Teacher(name, teachAge) {
      println("SeniorTeacher start")
      println(desc)
      //desc = ""
    
      //被重写的属性必须是val修饰的属性
      override val school:String = "北大"
    
      override def teach(): Unit ={
        println(s"$name SeniorTeacher is teaching ...")
      }
    
      println("SeniorTeacher end")
    }
    
    val t1 = new SeniorTeacher("小孔", "教龄18",18)
    println(t1.school)
    t1.teach
    
    

    5.4 抽象类的使用

    抽象函数的声明:

    • 抽象函数必须使用abstract修饰;
    • 抽象函数的全局变量可赋值也可不赋值;
    • 抽象函数可有有一个或多个方法未实现;

    继承抽象函数:

    • 继承抽象函数时,没有赋值的属性必须赋值,没有实现的方法必须实现
    • 在实现属性/方法的时候可以使用override关键字,但是不使用也可以。
    • 被继承的抽象类属性不能使用var来修饰,这样做的好处是防止父类修改子类重写的属性。
    abstract class Order {
    
      val oid: Long
      val name: String
      val price: Double
    
      def orderInfo
    
    }
    
    class WaitPayOrder extends Order {
      override val oid: Long = 100001L
      override val name: String = ""
      override val price: Double = 100.0d
    
      override def orderInfo: Unit = {
        println("oid = " + oid, "name = " + name, "price = " + price)
      }
    }
    
    object AbstractClassDemo {
      def main(args: Array[String]): Unit = {
        val waitPayOrder = new WaitPayOrder
        println(waitPayOrder.oid)
        waitPayOrder.orderInfo
      }
    }
    
    

    5.5 trait接口

    trait 类似于 Java 的 interface ,其用法与abstract class一致,只不过abstract class可以使用构造器而trait不可以, 用法如下:

    trait Person{
      var name:String
      var age:Int
    
      def speak(): Unit ={
        println("speak...")
      }
    
      def eat
    }
    
    class Student extends Person{
      override var name: String = _
      override var age: Int = _
    
      override def eat: Unit = {
        print(s"$name is eating...")
      }
    }
    
    

    什么时候应该使用trait而不是抽象类? 如果你想定义一个类似接口的类型, 你可能会在trait和抽象类之间难以取舍. 这两种形式都可以让你定义一个类型的一些行为, 并要求继承者定义一些其他行为. 一些经验法则:

    1. 优先使用trait. 一个类扩展多个trait是很方便的, 但却只能扩展一个抽象类.

    2. 如果你需要构造函数参数, 使用抽象类. 因为抽象类可以定义带参数的构造函数, 而trait不行.

    5.6 伴生类和伴生对象

    假如一个class与object同时修饰ObjectDemo,此时class ObjectDemo叫做object ObjectDemo的伴生类;而object ObjectDemo叫做class ObjectDemo的伴生对象,如下:

    class ObjectDemo { }
    object ObjectDemo{ }
    
    object Test {
    
      def main(args: Array[String]): Unit = {
        val o1 = new ObjectDemo
        val o2 = ObjectDemo
        //(o1 = ObjectDemo@5ebec15,o2 = ObjectDemo$@21bcffb5)
        println("o1 = " + o1, "o2 = " + o2)
      }
    }
    
    

    伴生对象是一个单例对象:

    object ObjectDemo {
      var element = 0
    
      def increase {
        element += 1
      }
    }
    
    //调用如下
    for (i <- 1 to 10) {
        ObjectDemo.increase
    }
    println(ObjectDemo.element)    //10
    
    

    通过伴生对象的apply方法实现对象的初始化(如果调用伴生对象(),则会间接apply()方法,可以在该方法中实现对象的初始化 ):

    object ObjectDemo {
      def apply() = {
        new ObjectDemo
      }
      ...
    }
    
    //调用如下
    val od1 = ObjectDemo()
    val od2 = ObjectDemo()
    //(od1 = ObjectDemo@5ebec15,od2 = ObjectDemo@21bcffb5)
    println("od1 = " + od1, "od2 = " + od2)
    

    想获取更多技术视频,请前往叩丁狼官网:http://www.wolfcode.cn/openClassWeb_listDetail.html

    相关文章

      网友评论

          本文标题:Scala中的面向对象

          本文链接:https://www.haomeiwen.com/subject/picbtqtx.html